[llvm] [X86] Prefer SIMD min/max/abs for scalars when staying in XMM domain (PR #210654)

Simon Pilgrim via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 13 11:06:48 PDT 2026


================
@@ -0,0 +1,1729 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+sse2 | FileCheck %s --check-prefixes=SSE2
+; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+sse4.1 | FileCheck %s --check-prefixes=SSE41
+; RUN: llc < %s -mtriple=i686-unknown-unknown -mattr=+sse4.1 | FileCheck %s --check-prefixes=X86-SSE41
+; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+avx | FileCheck %s --check-prefixes=AVX
+; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+avx512f | FileCheck %s --check-prefixes=AVX512F
+; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+avx512f,+avx512vl | FileCheck %s --check-prefixes=AVX512VL
+; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+avx512fp16 | FileCheck %s --check-prefixes=AVX512FP16
+
+; Memory-bound sort2 (#210569): prefer vpmin/vpmax over cmp+cmov.
+define void @sort2_i32(ptr %a) nounwind {
+; SSE2-LABEL: sort2_i32:
+; SSE2:       # %bb.0:
+; SSE2-NEXT:    movl (%rdi), %eax
+; SSE2-NEXT:    movl 4(%rdi), %ecx
+; SSE2-NEXT:    cmpl %ecx, %eax
+; SSE2-NEXT:    movl %ecx, %edx
+; SSE2-NEXT:    cmovll %eax, %edx
+; SSE2-NEXT:    cmovgl %eax, %ecx
+; SSE2-NEXT:    movl %edx, (%rdi)
+; SSE2-NEXT:    movl %ecx, 4(%rdi)
+; SSE2-NEXT:    retq
+;
+; SSE41-LABEL: sort2_i32:
+; SSE41:       # %bb.0:
+; SSE41-NEXT:    movd {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; SSE41-NEXT:    movd {{.*#+}} xmm1 = mem[0],zero,zero,zero
+; SSE41-NEXT:    movdqa %xmm1, %xmm2
+; SSE41-NEXT:    pminsd %xmm0, %xmm2
+; SSE41-NEXT:    movd %xmm2, (%rdi)
+; SSE41-NEXT:    pmaxsd %xmm0, %xmm1
+; SSE41-NEXT:    movd %xmm1, 4(%rdi)
+; SSE41-NEXT:    retq
+;
+; X86-SSE41-LABEL: sort2_i32:
+; X86-SSE41:       # %bb.0:
+; X86-SSE41-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-SSE41-NEXT:    movd {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; X86-SSE41-NEXT:    movd {{.*#+}} xmm1 = mem[0],zero,zero,zero
+; X86-SSE41-NEXT:    movdqa %xmm1, %xmm2
+; X86-SSE41-NEXT:    pminsd %xmm0, %xmm2
+; X86-SSE41-NEXT:    movd %xmm2, (%eax)
+; X86-SSE41-NEXT:    pmaxsd %xmm0, %xmm1
+; X86-SSE41-NEXT:    movd %xmm1, 4(%eax)
+; X86-SSE41-NEXT:    retl
+;
+; AVX-LABEL: sort2_i32:
+; AVX:       # %bb.0:
+; AVX-NEXT:    vmovd {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; AVX-NEXT:    vmovd {{.*#+}} xmm1 = mem[0],zero,zero,zero
+; AVX-NEXT:    vpminsd %xmm0, %xmm1, %xmm2
+; AVX-NEXT:    vmovd %xmm2, (%rdi)
+; AVX-NEXT:    vpmaxsd %xmm0, %xmm1, %xmm0
+; AVX-NEXT:    vmovd %xmm0, 4(%rdi)
+; AVX-NEXT:    retq
+;
+; AVX512F-LABEL: sort2_i32:
+; AVX512F:       # %bb.0:
+; AVX512F-NEXT:    vmovd {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; AVX512F-NEXT:    vmovd {{.*#+}} xmm1 = mem[0],zero,zero,zero
+; AVX512F-NEXT:    vpminsd %xmm0, %xmm1, %xmm2
+; AVX512F-NEXT:    vmovd %xmm2, (%rdi)
+; AVX512F-NEXT:    vpmaxsd %xmm0, %xmm1, %xmm0
+; AVX512F-NEXT:    vmovd %xmm0, 4(%rdi)
+; AVX512F-NEXT:    retq
+;
+; AVX512VL-LABEL: sort2_i32:
+; AVX512VL:       # %bb.0:
+; AVX512VL-NEXT:    vmovd {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; AVX512VL-NEXT:    vmovd {{.*#+}} xmm1 = mem[0],zero,zero,zero
+; AVX512VL-NEXT:    vpminsd %xmm0, %xmm1, %xmm2
+; AVX512VL-NEXT:    vmovd %xmm2, (%rdi)
+; AVX512VL-NEXT:    vpmaxsd %xmm0, %xmm1, %xmm0
+; AVX512VL-NEXT:    vmovd %xmm0, 4(%rdi)
+; AVX512VL-NEXT:    retq
+;
+; AVX512FP16-LABEL: sort2_i32:
+; AVX512FP16:       # %bb.0:
+; AVX512FP16-NEXT:    vmovd {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; AVX512FP16-NEXT:    vmovd {{.*#+}} xmm1 = mem[0],zero,zero,zero
+; AVX512FP16-NEXT:    vpminsd %xmm0, %xmm1, %xmm2
+; AVX512FP16-NEXT:    vmovd %xmm2, (%rdi)
+; AVX512FP16-NEXT:    vpmaxsd %xmm0, %xmm1, %xmm0
+; AVX512FP16-NEXT:    vmovd %xmm0, 4(%rdi)
+; AVX512FP16-NEXT:    retq
+  %p0 = getelementptr inbounds i32, ptr %a, i64 0
+  %p1 = getelementptr inbounds i32, ptr %a, i64 1
+  %x = load i32, ptr %p0, align 4
+  %y = load i32, ptr %p1, align 4
+  %lo = call i32 @llvm.smin.i32(i32 %x, i32 %y)
+  %hi = call i32 @llvm.smax.i32(i32 %x, i32 %y)
+  store i32 %lo, ptr %p0, align 4
+  store i32 %hi, ptr %p1, align 4
+  ret void
+}
+
+define void @store_smin_i32(ptr %p, ptr %q, ptr %r) nounwind {
+; SSE2-LABEL: store_smin_i32:
+; SSE2:       # %bb.0:
+; SSE2-NEXT:    movl (%rdi), %eax
+; SSE2-NEXT:    movl (%rsi), %ecx
+; SSE2-NEXT:    cmpl %ecx, %eax
+; SSE2-NEXT:    cmovll %eax, %ecx
+; SSE2-NEXT:    movl %ecx, (%rdx)
+; SSE2-NEXT:    retq
+;
+; SSE41-LABEL: store_smin_i32:
+; SSE41:       # %bb.0:
+; SSE41-NEXT:    movd {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; SSE41-NEXT:    movd {{.*#+}} xmm1 = mem[0],zero,zero,zero
+; SSE41-NEXT:    pminsd %xmm0, %xmm1
+; SSE41-NEXT:    movd %xmm1, (%rdx)
+; SSE41-NEXT:    retq
+;
+; X86-SSE41-LABEL: store_smin_i32:
+; X86-SSE41:       # %bb.0:
+; X86-SSE41-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-SSE41-NEXT:    movl {{[0-9]+}}(%esp), %ecx
+; X86-SSE41-NEXT:    movl {{[0-9]+}}(%esp), %edx
+; X86-SSE41-NEXT:    movd {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; X86-SSE41-NEXT:    movd {{.*#+}} xmm1 = mem[0],zero,zero,zero
+; X86-SSE41-NEXT:    pminsd %xmm0, %xmm1
+; X86-SSE41-NEXT:    movd %xmm1, (%eax)
+; X86-SSE41-NEXT:    retl
+;
+; AVX-LABEL: store_smin_i32:
+; AVX:       # %bb.0:
+; AVX-NEXT:    vmovd {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; AVX-NEXT:    vmovd {{.*#+}} xmm1 = mem[0],zero,zero,zero
+; AVX-NEXT:    vpminsd %xmm0, %xmm1, %xmm0
+; AVX-NEXT:    vmovd %xmm0, (%rdx)
+; AVX-NEXT:    retq
+;
+; AVX512F-LABEL: store_smin_i32:
+; AVX512F:       # %bb.0:
+; AVX512F-NEXT:    vmovd {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; AVX512F-NEXT:    vmovd {{.*#+}} xmm1 = mem[0],zero,zero,zero
+; AVX512F-NEXT:    vpminsd %xmm0, %xmm1, %xmm0
+; AVX512F-NEXT:    vmovd %xmm0, (%rdx)
+; AVX512F-NEXT:    retq
+;
+; AVX512VL-LABEL: store_smin_i32:
+; AVX512VL:       # %bb.0:
+; AVX512VL-NEXT:    vmovd {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; AVX512VL-NEXT:    vmovd {{.*#+}} xmm1 = mem[0],zero,zero,zero
+; AVX512VL-NEXT:    vpminsd %xmm0, %xmm1, %xmm0
+; AVX512VL-NEXT:    vmovd %xmm0, (%rdx)
+; AVX512VL-NEXT:    retq
+;
+; AVX512FP16-LABEL: store_smin_i32:
+; AVX512FP16:       # %bb.0:
+; AVX512FP16-NEXT:    vmovd {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; AVX512FP16-NEXT:    vmovd {{.*#+}} xmm1 = mem[0],zero,zero,zero
+; AVX512FP16-NEXT:    vpminsd %xmm0, %xmm1, %xmm0
+; AVX512FP16-NEXT:    vmovd %xmm0, (%rdx)
+; AVX512FP16-NEXT:    retq
+  %x = load i32, ptr %p, align 4
+  %y = load i32, ptr %q, align 4
+  %m = call i32 @llvm.smin.i32(i32 %x, i32 %y)
+  store i32 %m, ptr %r, align 4
+  ret void
+}
+
+define void @store_smax_i32(ptr %p, ptr %q, ptr %r) nounwind {
+; SSE2-LABEL: store_smax_i32:
+; SSE2:       # %bb.0:
+; SSE2-NEXT:    movl (%rdi), %eax
+; SSE2-NEXT:    movl (%rsi), %ecx
+; SSE2-NEXT:    cmpl %ecx, %eax
+; SSE2-NEXT:    cmovgl %eax, %ecx
+; SSE2-NEXT:    movl %ecx, (%rdx)
+; SSE2-NEXT:    retq
+;
+; SSE41-LABEL: store_smax_i32:
+; SSE41:       # %bb.0:
+; SSE41-NEXT:    movd {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; SSE41-NEXT:    movd {{.*#+}} xmm1 = mem[0],zero,zero,zero
+; SSE41-NEXT:    pmaxsd %xmm0, %xmm1
+; SSE41-NEXT:    movd %xmm1, (%rdx)
+; SSE41-NEXT:    retq
+;
+; X86-SSE41-LABEL: store_smax_i32:
+; X86-SSE41:       # %bb.0:
+; X86-SSE41-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-SSE41-NEXT:    movl {{[0-9]+}}(%esp), %ecx
+; X86-SSE41-NEXT:    movl {{[0-9]+}}(%esp), %edx
+; X86-SSE41-NEXT:    movd {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; X86-SSE41-NEXT:    movd {{.*#+}} xmm1 = mem[0],zero,zero,zero
+; X86-SSE41-NEXT:    pmaxsd %xmm0, %xmm1
+; X86-SSE41-NEXT:    movd %xmm1, (%eax)
+; X86-SSE41-NEXT:    retl
+;
+; AVX-LABEL: store_smax_i32:
+; AVX:       # %bb.0:
+; AVX-NEXT:    vmovd {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; AVX-NEXT:    vmovd {{.*#+}} xmm1 = mem[0],zero,zero,zero
+; AVX-NEXT:    vpmaxsd %xmm0, %xmm1, %xmm0
+; AVX-NEXT:    vmovd %xmm0, (%rdx)
+; AVX-NEXT:    retq
+;
+; AVX512F-LABEL: store_smax_i32:
+; AVX512F:       # %bb.0:
+; AVX512F-NEXT:    vmovd {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; AVX512F-NEXT:    vmovd {{.*#+}} xmm1 = mem[0],zero,zero,zero
+; AVX512F-NEXT:    vpmaxsd %xmm0, %xmm1, %xmm0
+; AVX512F-NEXT:    vmovd %xmm0, (%rdx)
+; AVX512F-NEXT:    retq
+;
+; AVX512VL-LABEL: store_smax_i32:
+; AVX512VL:       # %bb.0:
+; AVX512VL-NEXT:    vmovd {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; AVX512VL-NEXT:    vmovd {{.*#+}} xmm1 = mem[0],zero,zero,zero
+; AVX512VL-NEXT:    vpmaxsd %xmm0, %xmm1, %xmm0
+; AVX512VL-NEXT:    vmovd %xmm0, (%rdx)
+; AVX512VL-NEXT:    retq
+;
+; AVX512FP16-LABEL: store_smax_i32:
+; AVX512FP16:       # %bb.0:
+; AVX512FP16-NEXT:    vmovd {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; AVX512FP16-NEXT:    vmovd {{.*#+}} xmm1 = mem[0],zero,zero,zero
+; AVX512FP16-NEXT:    vpmaxsd %xmm0, %xmm1, %xmm0
+; AVX512FP16-NEXT:    vmovd %xmm0, (%rdx)
+; AVX512FP16-NEXT:    retq
+  %x = load i32, ptr %p, align 4
+  %y = load i32, ptr %q, align 4
+  %m = call i32 @llvm.smax.i32(i32 %x, i32 %y)
+  store i32 %m, ptr %r, align 4
+  ret void
+}
+
+define void @store_umin_i32(ptr %p, ptr %q, ptr %r) nounwind {
+; SSE2-LABEL: store_umin_i32:
+; SSE2:       # %bb.0:
+; SSE2-NEXT:    movl (%rdi), %eax
+; SSE2-NEXT:    movl (%rsi), %ecx
+; SSE2-NEXT:    cmpl %ecx, %eax
+; SSE2-NEXT:    cmovbl %eax, %ecx
+; SSE2-NEXT:    movl %ecx, (%rdx)
+; SSE2-NEXT:    retq
+;
+; SSE41-LABEL: store_umin_i32:
+; SSE41:       # %bb.0:
+; SSE41-NEXT:    movd {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; SSE41-NEXT:    movd {{.*#+}} xmm1 = mem[0],zero,zero,zero
+; SSE41-NEXT:    pminud %xmm0, %xmm1
+; SSE41-NEXT:    movd %xmm1, (%rdx)
+; SSE41-NEXT:    retq
+;
+; X86-SSE41-LABEL: store_umin_i32:
+; X86-SSE41:       # %bb.0:
+; X86-SSE41-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-SSE41-NEXT:    movl {{[0-9]+}}(%esp), %ecx
+; X86-SSE41-NEXT:    movl {{[0-9]+}}(%esp), %edx
+; X86-SSE41-NEXT:    movd {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; X86-SSE41-NEXT:    movd {{.*#+}} xmm1 = mem[0],zero,zero,zero
+; X86-SSE41-NEXT:    pminud %xmm0, %xmm1
+; X86-SSE41-NEXT:    movd %xmm1, (%eax)
+; X86-SSE41-NEXT:    retl
+;
+; AVX-LABEL: store_umin_i32:
+; AVX:       # %bb.0:
+; AVX-NEXT:    vmovd {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; AVX-NEXT:    vmovd {{.*#+}} xmm1 = mem[0],zero,zero,zero
+; AVX-NEXT:    vpminud %xmm0, %xmm1, %xmm0
+; AVX-NEXT:    vmovd %xmm0, (%rdx)
+; AVX-NEXT:    retq
+;
+; AVX512F-LABEL: store_umin_i32:
+; AVX512F:       # %bb.0:
+; AVX512F-NEXT:    vmovd {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; AVX512F-NEXT:    vmovd {{.*#+}} xmm1 = mem[0],zero,zero,zero
+; AVX512F-NEXT:    vpminud %xmm0, %xmm1, %xmm0
+; AVX512F-NEXT:    vmovd %xmm0, (%rdx)
+; AVX512F-NEXT:    retq
+;
+; AVX512VL-LABEL: store_umin_i32:
+; AVX512VL:       # %bb.0:
+; AVX512VL-NEXT:    vmovd {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; AVX512VL-NEXT:    vmovd {{.*#+}} xmm1 = mem[0],zero,zero,zero
+; AVX512VL-NEXT:    vpminud %xmm0, %xmm1, %xmm0
+; AVX512VL-NEXT:    vmovd %xmm0, (%rdx)
+; AVX512VL-NEXT:    retq
+;
+; AVX512FP16-LABEL: store_umin_i32:
+; AVX512FP16:       # %bb.0:
+; AVX512FP16-NEXT:    vmovd {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; AVX512FP16-NEXT:    vmovd {{.*#+}} xmm1 = mem[0],zero,zero,zero
+; AVX512FP16-NEXT:    vpminud %xmm0, %xmm1, %xmm0
+; AVX512FP16-NEXT:    vmovd %xmm0, (%rdx)
+; AVX512FP16-NEXT:    retq
+  %x = load i32, ptr %p, align 4
+  %y = load i32, ptr %q, align 4
+  %m = call i32 @llvm.umin.i32(i32 %x, i32 %y)
+  store i32 %m, ptr %r, align 4
+  ret void
+}
+
+define void @store_umax_i32(ptr %p, ptr %q, ptr %r) nounwind {
+; SSE2-LABEL: store_umax_i32:
+; SSE2:       # %bb.0:
+; SSE2-NEXT:    movl (%rdi), %eax
+; SSE2-NEXT:    movl (%rsi), %ecx
+; SSE2-NEXT:    cmpl %ecx, %eax
+; SSE2-NEXT:    cmoval %eax, %ecx
+; SSE2-NEXT:    movl %ecx, (%rdx)
+; SSE2-NEXT:    retq
+;
+; SSE41-LABEL: store_umax_i32:
+; SSE41:       # %bb.0:
+; SSE41-NEXT:    movd {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; SSE41-NEXT:    movd {{.*#+}} xmm1 = mem[0],zero,zero,zero
+; SSE41-NEXT:    pmaxud %xmm0, %xmm1
+; SSE41-NEXT:    movd %xmm1, (%rdx)
+; SSE41-NEXT:    retq
+;
+; X86-SSE41-LABEL: store_umax_i32:
+; X86-SSE41:       # %bb.0:
+; X86-SSE41-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-SSE41-NEXT:    movl {{[0-9]+}}(%esp), %ecx
+; X86-SSE41-NEXT:    movl {{[0-9]+}}(%esp), %edx
+; X86-SSE41-NEXT:    movd {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; X86-SSE41-NEXT:    movd {{.*#+}} xmm1 = mem[0],zero,zero,zero
+; X86-SSE41-NEXT:    pmaxud %xmm0, %xmm1
+; X86-SSE41-NEXT:    movd %xmm1, (%eax)
+; X86-SSE41-NEXT:    retl
+;
+; AVX-LABEL: store_umax_i32:
+; AVX:       # %bb.0:
+; AVX-NEXT:    vmovd {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; AVX-NEXT:    vmovd {{.*#+}} xmm1 = mem[0],zero,zero,zero
+; AVX-NEXT:    vpmaxud %xmm0, %xmm1, %xmm0
+; AVX-NEXT:    vmovd %xmm0, (%rdx)
+; AVX-NEXT:    retq
+;
+; AVX512F-LABEL: store_umax_i32:
+; AVX512F:       # %bb.0:
+; AVX512F-NEXT:    vmovd {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; AVX512F-NEXT:    vmovd {{.*#+}} xmm1 = mem[0],zero,zero,zero
+; AVX512F-NEXT:    vpmaxud %xmm0, %xmm1, %xmm0
+; AVX512F-NEXT:    vmovd %xmm0, (%rdx)
+; AVX512F-NEXT:    retq
+;
+; AVX512VL-LABEL: store_umax_i32:
+; AVX512VL:       # %bb.0:
+; AVX512VL-NEXT:    vmovd {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; AVX512VL-NEXT:    vmovd {{.*#+}} xmm1 = mem[0],zero,zero,zero
+; AVX512VL-NEXT:    vpmaxud %xmm0, %xmm1, %xmm0
+; AVX512VL-NEXT:    vmovd %xmm0, (%rdx)
+; AVX512VL-NEXT:    retq
+;
+; AVX512FP16-LABEL: store_umax_i32:
+; AVX512FP16:       # %bb.0:
+; AVX512FP16-NEXT:    vmovd {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; AVX512FP16-NEXT:    vmovd {{.*#+}} xmm1 = mem[0],zero,zero,zero
+; AVX512FP16-NEXT:    vpmaxud %xmm0, %xmm1, %xmm0
+; AVX512FP16-NEXT:    vmovd %xmm0, (%rdx)
+; AVX512FP16-NEXT:    retq
+  %x = load i32, ptr %p, align 4
+  %y = load i32, ptr %q, align 4
+  %m = call i32 @llvm.umax.i32(i32 %x, i32 %y)
+  store i32 %m, ptr %r, align 4
+  ret void
+}
+
+; Negative: register operands / GPR result should stay on CMOV.
+define i32 @smin_gpr(i32 %x, i32 %y) nounwind {
+; SSE2-LABEL: smin_gpr:
+; SSE2:       # %bb.0:
+; SSE2-NEXT:    movl %esi, %eax
+; SSE2-NEXT:    cmpl %esi, %edi
+; SSE2-NEXT:    cmovll %edi, %eax
+; SSE2-NEXT:    retq
+;
+; SSE41-LABEL: smin_gpr:
+; SSE41:       # %bb.0:
+; SSE41-NEXT:    movl %esi, %eax
+; SSE41-NEXT:    cmpl %esi, %edi
+; SSE41-NEXT:    cmovll %edi, %eax
+; SSE41-NEXT:    retq
+;
+; X86-SSE41-LABEL: smin_gpr:
+; X86-SSE41:       # %bb.0:
+; X86-SSE41-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-SSE41-NEXT:    movl {{[0-9]+}}(%esp), %ecx
+; X86-SSE41-NEXT:    cmpl %eax, %ecx
+; X86-SSE41-NEXT:    cmovll %ecx, %eax
+; X86-SSE41-NEXT:    retl
+;
+; AVX-LABEL: smin_gpr:
+; AVX:       # %bb.0:
+; AVX-NEXT:    movl %esi, %eax
+; AVX-NEXT:    cmpl %esi, %edi
+; AVX-NEXT:    cmovll %edi, %eax
+; AVX-NEXT:    retq
+;
+; AVX512F-LABEL: smin_gpr:
+; AVX512F:       # %bb.0:
+; AVX512F-NEXT:    movl %esi, %eax
+; AVX512F-NEXT:    cmpl %esi, %edi
+; AVX512F-NEXT:    cmovll %edi, %eax
+; AVX512F-NEXT:    retq
+;
+; AVX512VL-LABEL: smin_gpr:
+; AVX512VL:       # %bb.0:
+; AVX512VL-NEXT:    movl %esi, %eax
+; AVX512VL-NEXT:    cmpl %esi, %edi
+; AVX512VL-NEXT:    cmovll %edi, %eax
+; AVX512VL-NEXT:    retq
+;
+; AVX512FP16-LABEL: smin_gpr:
+; AVX512FP16:       # %bb.0:
+; AVX512FP16-NEXT:    movl %esi, %eax
+; AVX512FP16-NEXT:    cmpl %esi, %edi
+; AVX512FP16-NEXT:    cmovll %edi, %eax
+; AVX512FP16-NEXT:    retq
+  %m = call i32 @llvm.smin.i32(i32 %x, i32 %y)
+  ret i32 %m
+}
+
+define i32 @smin_load_to_gpr(ptr %p, ptr %q) nounwind {
+; SSE2-LABEL: smin_load_to_gpr:
+; SSE2:       # %bb.0:
+; SSE2-NEXT:    movl (%rdi), %ecx
+; SSE2-NEXT:    movl (%rsi), %eax
+; SSE2-NEXT:    cmpl %eax, %ecx
+; SSE2-NEXT:    cmovll %ecx, %eax
+; SSE2-NEXT:    retq
+;
+; SSE41-LABEL: smin_load_to_gpr:
+; SSE41:       # %bb.0:
+; SSE41-NEXT:    movl (%rdi), %ecx
+; SSE41-NEXT:    movl (%rsi), %eax
+; SSE41-NEXT:    cmpl %eax, %ecx
+; SSE41-NEXT:    cmovll %ecx, %eax
+; SSE41-NEXT:    retq
+;
+; X86-SSE41-LABEL: smin_load_to_gpr:
+; X86-SSE41:       # %bb.0:
+; X86-SSE41-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-SSE41-NEXT:    movl {{[0-9]+}}(%esp), %ecx
+; X86-SSE41-NEXT:    movl (%ecx), %ecx
+; X86-SSE41-NEXT:    movl (%eax), %eax
+; X86-SSE41-NEXT:    cmpl %eax, %ecx
+; X86-SSE41-NEXT:    cmovll %ecx, %eax
+; X86-SSE41-NEXT:    retl
+;
+; AVX-LABEL: smin_load_to_gpr:
+; AVX:       # %bb.0:
+; AVX-NEXT:    movl (%rdi), %ecx
+; AVX-NEXT:    movl (%rsi), %eax
+; AVX-NEXT:    cmpl %eax, %ecx
+; AVX-NEXT:    cmovll %ecx, %eax
+; AVX-NEXT:    retq
+;
+; AVX512F-LABEL: smin_load_to_gpr:
+; AVX512F:       # %bb.0:
+; AVX512F-NEXT:    movl (%rdi), %ecx
+; AVX512F-NEXT:    movl (%rsi), %eax
+; AVX512F-NEXT:    cmpl %eax, %ecx
+; AVX512F-NEXT:    cmovll %ecx, %eax
+; AVX512F-NEXT:    retq
+;
+; AVX512VL-LABEL: smin_load_to_gpr:
+; AVX512VL:       # %bb.0:
+; AVX512VL-NEXT:    movl (%rdi), %ecx
+; AVX512VL-NEXT:    movl (%rsi), %eax
+; AVX512VL-NEXT:    cmpl %eax, %ecx
+; AVX512VL-NEXT:    cmovll %ecx, %eax
+; AVX512VL-NEXT:    retq
+;
+; AVX512FP16-LABEL: smin_load_to_gpr:
+; AVX512FP16:       # %bb.0:
+; AVX512FP16-NEXT:    movl (%rdi), %ecx
+; AVX512FP16-NEXT:    movl (%rsi), %eax
+; AVX512FP16-NEXT:    cmpl %eax, %ecx
+; AVX512FP16-NEXT:    cmovll %ecx, %eax
+; AVX512FP16-NEXT:    retq
+  %x = load i32, ptr %p, align 4
+  %y = load i32, ptr %q, align 4
+  %m = call i32 @llvm.smin.i32(i32 %x, i32 %y)
+  ret i32 %m
+}
+
+; Negative: noimplicitfloat must not introduce XMM ops.
+define void @sort2_i32_noimplicitfloat(ptr %a) nounwind noimplicitfloat {
+; SSE2-LABEL: sort2_i32_noimplicitfloat:
+; SSE2:       # %bb.0:
+; SSE2-NEXT:    movl (%rdi), %eax
+; SSE2-NEXT:    movl 4(%rdi), %ecx
+; SSE2-NEXT:    cmpl %ecx, %eax
+; SSE2-NEXT:    movl %ecx, %edx
+; SSE2-NEXT:    cmovll %eax, %edx
+; SSE2-NEXT:    cmovgl %eax, %ecx
+; SSE2-NEXT:    movl %edx, (%rdi)
+; SSE2-NEXT:    movl %ecx, 4(%rdi)
+; SSE2-NEXT:    retq
+;
+; SSE41-LABEL: sort2_i32_noimplicitfloat:
+; SSE41:       # %bb.0:
+; SSE41-NEXT:    movl (%rdi), %eax
+; SSE41-NEXT:    movl 4(%rdi), %ecx
+; SSE41-NEXT:    cmpl %ecx, %eax
+; SSE41-NEXT:    movl %ecx, %edx
+; SSE41-NEXT:    cmovll %eax, %edx
+; SSE41-NEXT:    cmovgl %eax, %ecx
+; SSE41-NEXT:    movl %edx, (%rdi)
+; SSE41-NEXT:    movl %ecx, 4(%rdi)
+; SSE41-NEXT:    retq
+;
+; X86-SSE41-LABEL: sort2_i32_noimplicitfloat:
+; X86-SSE41:       # %bb.0:
+; X86-SSE41-NEXT:    pushl %esi
+; X86-SSE41-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-SSE41-NEXT:    movl (%eax), %ecx
+; X86-SSE41-NEXT:    movl 4(%eax), %edx
+; X86-SSE41-NEXT:    cmpl %edx, %ecx
+; X86-SSE41-NEXT:    movl %edx, %esi
+; X86-SSE41-NEXT:    cmovll %ecx, %esi
+; X86-SSE41-NEXT:    cmovgl %ecx, %edx
+; X86-SSE41-NEXT:    movl %esi, (%eax)
+; X86-SSE41-NEXT:    movl %edx, 4(%eax)
+; X86-SSE41-NEXT:    popl %esi
+; X86-SSE41-NEXT:    retl
+;
+; AVX-LABEL: sort2_i32_noimplicitfloat:
+; AVX:       # %bb.0:
+; AVX-NEXT:    movl (%rdi), %eax
+; AVX-NEXT:    movl 4(%rdi), %ecx
+; AVX-NEXT:    cmpl %ecx, %eax
+; AVX-NEXT:    movl %ecx, %edx
+; AVX-NEXT:    cmovll %eax, %edx
+; AVX-NEXT:    cmovgl %eax, %ecx
+; AVX-NEXT:    movl %edx, (%rdi)
+; AVX-NEXT:    movl %ecx, 4(%rdi)
+; AVX-NEXT:    retq
+;
+; AVX512F-LABEL: sort2_i32_noimplicitfloat:
+; AVX512F:       # %bb.0:
+; AVX512F-NEXT:    movl (%rdi), %eax
+; AVX512F-NEXT:    movl 4(%rdi), %ecx
+; AVX512F-NEXT:    cmpl %ecx, %eax
+; AVX512F-NEXT:    movl %ecx, %edx
+; AVX512F-NEXT:    cmovll %eax, %edx
+; AVX512F-NEXT:    cmovgl %eax, %ecx
+; AVX512F-NEXT:    movl %edx, (%rdi)
+; AVX512F-NEXT:    movl %ecx, 4(%rdi)
+; AVX512F-NEXT:    retq
+;
+; AVX512VL-LABEL: sort2_i32_noimplicitfloat:
+; AVX512VL:       # %bb.0:
+; AVX512VL-NEXT:    movl (%rdi), %eax
+; AVX512VL-NEXT:    movl 4(%rdi), %ecx
+; AVX512VL-NEXT:    cmpl %ecx, %eax
+; AVX512VL-NEXT:    movl %ecx, %edx
+; AVX512VL-NEXT:    cmovll %eax, %edx
+; AVX512VL-NEXT:    cmovgl %eax, %ecx
+; AVX512VL-NEXT:    movl %edx, (%rdi)
+; AVX512VL-NEXT:    movl %ecx, 4(%rdi)
+; AVX512VL-NEXT:    retq
+;
+; AVX512FP16-LABEL: sort2_i32_noimplicitfloat:
+; AVX512FP16:       # %bb.0:
+; AVX512FP16-NEXT:    movl (%rdi), %eax
+; AVX512FP16-NEXT:    movl 4(%rdi), %ecx
+; AVX512FP16-NEXT:    cmpl %ecx, %eax
+; AVX512FP16-NEXT:    movl %ecx, %edx
+; AVX512FP16-NEXT:    cmovll %eax, %edx
+; AVX512FP16-NEXT:    cmovgl %eax, %ecx
+; AVX512FP16-NEXT:    movl %edx, (%rdi)
+; AVX512FP16-NEXT:    movl %ecx, 4(%rdi)
+; AVX512FP16-NEXT:    retq
+  %p0 = getelementptr inbounds i32, ptr %a, i64 0
+  %p1 = getelementptr inbounds i32, ptr %a, i64 1
+  %x = load i32, ptr %p0, align 4
+  %y = load i32, ptr %p1, align 4
+  %lo = call i32 @llvm.smin.i32(i32 %x, i32 %y)
+  %hi = call i32 @llvm.smax.i32(i32 %x, i32 %y)
+  store i32 %lo, ptr %p0, align 4
+  store i32 %hi, ptr %p1, align 4
+  ret void
+}
+
+; Negative: optsize prefers compact cmp+cmov over movd+pmin/pmax.
+define void @sort2_i32_optsize(ptr %a) nounwind optsize {
+; SSE2-LABEL: sort2_i32_optsize:
+; SSE2:       # %bb.0:
+; SSE2-NEXT:    movl (%rdi), %eax
+; SSE2-NEXT:    movl 4(%rdi), %ecx
+; SSE2-NEXT:    cmpl %ecx, %eax
+; SSE2-NEXT:    movl %ecx, %edx
+; SSE2-NEXT:    cmovll %eax, %edx
+; SSE2-NEXT:    cmovgl %eax, %ecx
+; SSE2-NEXT:    movl %edx, (%rdi)
+; SSE2-NEXT:    movl %ecx, 4(%rdi)
+; SSE2-NEXT:    retq
+;
+; SSE41-LABEL: sort2_i32_optsize:
+; SSE41:       # %bb.0:
+; SSE41-NEXT:    movl (%rdi), %eax
+; SSE41-NEXT:    movl 4(%rdi), %ecx
+; SSE41-NEXT:    cmpl %ecx, %eax
+; SSE41-NEXT:    movl %ecx, %edx
+; SSE41-NEXT:    cmovll %eax, %edx
+; SSE41-NEXT:    cmovgl %eax, %ecx
+; SSE41-NEXT:    movl %edx, (%rdi)
+; SSE41-NEXT:    movl %ecx, 4(%rdi)
+; SSE41-NEXT:    retq
+;
+; X86-SSE41-LABEL: sort2_i32_optsize:
+; X86-SSE41:       # %bb.0:
+; X86-SSE41-NEXT:    pushl %esi
+; X86-SSE41-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-SSE41-NEXT:    movl (%eax), %ecx
+; X86-SSE41-NEXT:    movl 4(%eax), %edx
+; X86-SSE41-NEXT:    cmpl %edx, %ecx
+; X86-SSE41-NEXT:    movl %edx, %esi
+; X86-SSE41-NEXT:    cmovll %ecx, %esi
+; X86-SSE41-NEXT:    cmovgl %ecx, %edx
+; X86-SSE41-NEXT:    movl %esi, (%eax)
+; X86-SSE41-NEXT:    movl %edx, 4(%eax)
+; X86-SSE41-NEXT:    popl %esi
+; X86-SSE41-NEXT:    retl
+;
+; AVX-LABEL: sort2_i32_optsize:
+; AVX:       # %bb.0:
+; AVX-NEXT:    movl (%rdi), %eax
+; AVX-NEXT:    movl 4(%rdi), %ecx
+; AVX-NEXT:    cmpl %ecx, %eax
+; AVX-NEXT:    movl %ecx, %edx
+; AVX-NEXT:    cmovll %eax, %edx
+; AVX-NEXT:    cmovgl %eax, %ecx
+; AVX-NEXT:    movl %edx, (%rdi)
+; AVX-NEXT:    movl %ecx, 4(%rdi)
+; AVX-NEXT:    retq
+;
+; AVX512F-LABEL: sort2_i32_optsize:
+; AVX512F:       # %bb.0:
+; AVX512F-NEXT:    movl (%rdi), %eax
+; AVX512F-NEXT:    movl 4(%rdi), %ecx
+; AVX512F-NEXT:    cmpl %ecx, %eax
+; AVX512F-NEXT:    movl %ecx, %edx
+; AVX512F-NEXT:    cmovll %eax, %edx
+; AVX512F-NEXT:    cmovgl %eax, %ecx
+; AVX512F-NEXT:    movl %edx, (%rdi)
+; AVX512F-NEXT:    movl %ecx, 4(%rdi)
+; AVX512F-NEXT:    retq
+;
+; AVX512VL-LABEL: sort2_i32_optsize:
+; AVX512VL:       # %bb.0:
+; AVX512VL-NEXT:    movl (%rdi), %eax
+; AVX512VL-NEXT:    movl 4(%rdi), %ecx
+; AVX512VL-NEXT:    cmpl %ecx, %eax
+; AVX512VL-NEXT:    movl %ecx, %edx
+; AVX512VL-NEXT:    cmovll %eax, %edx
+; AVX512VL-NEXT:    cmovgl %eax, %ecx
+; AVX512VL-NEXT:    movl %edx, (%rdi)
+; AVX512VL-NEXT:    movl %ecx, 4(%rdi)
+; AVX512VL-NEXT:    retq
+;
+; AVX512FP16-LABEL: sort2_i32_optsize:
+; AVX512FP16:       # %bb.0:
+; AVX512FP16-NEXT:    movl (%rdi), %eax
+; AVX512FP16-NEXT:    movl 4(%rdi), %ecx
+; AVX512FP16-NEXT:    cmpl %ecx, %eax
+; AVX512FP16-NEXT:    movl %ecx, %edx
+; AVX512FP16-NEXT:    cmovll %eax, %edx
+; AVX512FP16-NEXT:    cmovgl %eax, %ecx
+; AVX512FP16-NEXT:    movl %edx, (%rdi)
+; AVX512FP16-NEXT:    movl %ecx, 4(%rdi)
+; AVX512FP16-NEXT:    retq
+  %p0 = getelementptr inbounds i32, ptr %a, i64 0
+  %p1 = getelementptr inbounds i32, ptr %a, i64 1
+  %x = load i32, ptr %p0, align 4
+  %y = load i32, ptr %p1, align 4
+  %lo = call i32 @llvm.smin.i32(i32 %x, i32 %y)
+  %hi = call i32 @llvm.smax.i32(i32 %x, i32 %y)
+  store i32 %lo, ptr %p0, align 4
+  store i32 %hi, ptr %p1, align 4
+  ret void
+}
+
+; Negative: constant operands are not XMM-native sources; stay on CMOV.
+define void @store_smin_load_const(ptr %p, ptr %r) nounwind {
+; SSE2-LABEL: store_smin_load_const:
+; SSE2:       # %bb.0:
+; SSE2-NEXT:    movl (%rdi), %eax
+; SSE2-NEXT:    cmpl $5, %eax
+; SSE2-NEXT:    movl $5, %ecx
+; SSE2-NEXT:    cmovll %eax, %ecx
+; SSE2-NEXT:    movl %ecx, (%rsi)
+; SSE2-NEXT:    retq
+;
+; SSE41-LABEL: store_smin_load_const:
+; SSE41:       # %bb.0:
+; SSE41-NEXT:    movl (%rdi), %eax
+; SSE41-NEXT:    cmpl $5, %eax
+; SSE41-NEXT:    movl $5, %ecx
+; SSE41-NEXT:    cmovll %eax, %ecx
+; SSE41-NEXT:    movl %ecx, (%rsi)
+; SSE41-NEXT:    retq
+;
+; X86-SSE41-LABEL: store_smin_load_const:
+; X86-SSE41:       # %bb.0:
+; X86-SSE41-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-SSE41-NEXT:    movl {{[0-9]+}}(%esp), %ecx
+; X86-SSE41-NEXT:    movl (%ecx), %ecx
+; X86-SSE41-NEXT:    cmpl $5, %ecx
+; X86-SSE41-NEXT:    movl $5, %edx
+; X86-SSE41-NEXT:    cmovll %ecx, %edx
+; X86-SSE41-NEXT:    movl %edx, (%eax)
+; X86-SSE41-NEXT:    retl
+;
+; AVX-LABEL: store_smin_load_const:
+; AVX:       # %bb.0:
+; AVX-NEXT:    movl (%rdi), %eax
+; AVX-NEXT:    cmpl $5, %eax
+; AVX-NEXT:    movl $5, %ecx
+; AVX-NEXT:    cmovll %eax, %ecx
+; AVX-NEXT:    movl %ecx, (%rsi)
+; AVX-NEXT:    retq
+;
+; AVX512F-LABEL: store_smin_load_const:
+; AVX512F:       # %bb.0:
+; AVX512F-NEXT:    movl (%rdi), %eax
+; AVX512F-NEXT:    cmpl $5, %eax
+; AVX512F-NEXT:    movl $5, %ecx
+; AVX512F-NEXT:    cmovll %eax, %ecx
+; AVX512F-NEXT:    movl %ecx, (%rsi)
+; AVX512F-NEXT:    retq
+;
+; AVX512VL-LABEL: store_smin_load_const:
+; AVX512VL:       # %bb.0:
+; AVX512VL-NEXT:    movl (%rdi), %eax
+; AVX512VL-NEXT:    cmpl $5, %eax
+; AVX512VL-NEXT:    movl $5, %ecx
+; AVX512VL-NEXT:    cmovll %eax, %ecx
+; AVX512VL-NEXT:    movl %ecx, (%rsi)
+; AVX512VL-NEXT:    retq
+;
+; AVX512FP16-LABEL: store_smin_load_const:
+; AVX512FP16:       # %bb.0:
+; AVX512FP16-NEXT:    movl (%rdi), %eax
+; AVX512FP16-NEXT:    cmpl $5, %eax
+; AVX512FP16-NEXT:    movl $5, %ecx
+; AVX512FP16-NEXT:    cmovll %eax, %ecx
+; AVX512FP16-NEXT:    movl %ecx, (%rsi)
+; AVX512FP16-NEXT:    retq
+  %x = load i32, ptr %p, align 4
+  %m = call i32 @llvm.smin.i32(i32 %x, i32 5)
+  store i32 %m, ptr %r, align 4
+  ret void
+}
+
+; Memory-bound abs (#210569): prefer pabsd over neg+cmov.
+define void @store_abs_i32(ptr %p, ptr %r) nounwind {
+; SSE2-LABEL: store_abs_i32:
+; SSE2:       # %bb.0:
+; SSE2-NEXT:    movl (%rdi), %eax
+; SSE2-NEXT:    movl %eax, %ecx
+; SSE2-NEXT:    negl %ecx
+; SSE2-NEXT:    cmovsl %eax, %ecx
+; SSE2-NEXT:    movl %ecx, (%rsi)
+; SSE2-NEXT:    retq
+;
+; SSE41-LABEL: store_abs_i32:
+; SSE41:       # %bb.0:
+; SSE41-NEXT:    movd {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; SSE41-NEXT:    pabsd %xmm0, %xmm0
+; SSE41-NEXT:    movd %xmm0, (%rsi)
+; SSE41-NEXT:    retq
+;
+; X86-SSE41-LABEL: store_abs_i32:
+; X86-SSE41:       # %bb.0:
+; X86-SSE41-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-SSE41-NEXT:    movl {{[0-9]+}}(%esp), %ecx
+; X86-SSE41-NEXT:    movd {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; X86-SSE41-NEXT:    pabsd %xmm0, %xmm0
+; X86-SSE41-NEXT:    movd %xmm0, (%eax)
+; X86-SSE41-NEXT:    retl
+;
+; AVX-LABEL: store_abs_i32:
+; AVX:       # %bb.0:
+; AVX-NEXT:    vmovd {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; AVX-NEXT:    vpabsd %xmm0, %xmm0
+; AVX-NEXT:    vmovd %xmm0, (%rsi)
+; AVX-NEXT:    retq
+;
+; AVX512F-LABEL: store_abs_i32:
+; AVX512F:       # %bb.0:
+; AVX512F-NEXT:    vmovd {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; AVX512F-NEXT:    vpabsd %xmm0, %xmm0
+; AVX512F-NEXT:    vmovd %xmm0, (%rsi)
+; AVX512F-NEXT:    retq
+;
+; AVX512VL-LABEL: store_abs_i32:
+; AVX512VL:       # %bb.0:
+; AVX512VL-NEXT:    vmovd {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; AVX512VL-NEXT:    vpabsd %xmm0, %xmm0
+; AVX512VL-NEXT:    vmovd %xmm0, (%rsi)
+; AVX512VL-NEXT:    retq
+;
+; AVX512FP16-LABEL: store_abs_i32:
+; AVX512FP16:       # %bb.0:
+; AVX512FP16-NEXT:    vmovd {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; AVX512FP16-NEXT:    vpabsd %xmm0, %xmm0
+; AVX512FP16-NEXT:    vmovd %xmm0, (%rsi)
+; AVX512FP16-NEXT:    retq
+  %x = load i32, ptr %p, align 4
+  %a = call i32 @llvm.abs.i32(i32 %x, i1 false)
+  store i32 %a, ptr %r, align 4
+  ret void
+}
+
+; Negative: register operand / GPR result should stay on neg+cmov.
+define i32 @abs_gpr(i32 %x) nounwind {
+; SSE2-LABEL: abs_gpr:
+; SSE2:       # %bb.0:
+; SSE2-NEXT:    movl %edi, %eax
+; SSE2-NEXT:    negl %eax
+; SSE2-NEXT:    cmovsl %edi, %eax
+; SSE2-NEXT:    retq
+;
+; SSE41-LABEL: abs_gpr:
+; SSE41:       # %bb.0:
+; SSE41-NEXT:    movl %edi, %eax
+; SSE41-NEXT:    negl %eax
+; SSE41-NEXT:    cmovsl %edi, %eax
+; SSE41-NEXT:    retq
+;
+; X86-SSE41-LABEL: abs_gpr:
+; X86-SSE41:       # %bb.0:
+; X86-SSE41-NEXT:    movl {{[0-9]+}}(%esp), %ecx
+; X86-SSE41-NEXT:    movl %ecx, %eax
+; X86-SSE41-NEXT:    negl %eax
+; X86-SSE41-NEXT:    cmovsl %ecx, %eax
+; X86-SSE41-NEXT:    retl
+;
+; AVX-LABEL: abs_gpr:
+; AVX:       # %bb.0:
+; AVX-NEXT:    movl %edi, %eax
+; AVX-NEXT:    negl %eax
+; AVX-NEXT:    cmovsl %edi, %eax
+; AVX-NEXT:    retq
+;
+; AVX512F-LABEL: abs_gpr:
+; AVX512F:       # %bb.0:
+; AVX512F-NEXT:    movl %edi, %eax
+; AVX512F-NEXT:    negl %eax
+; AVX512F-NEXT:    cmovsl %edi, %eax
+; AVX512F-NEXT:    retq
+;
+; AVX512VL-LABEL: abs_gpr:
+; AVX512VL:       # %bb.0:
+; AVX512VL-NEXT:    movl %edi, %eax
+; AVX512VL-NEXT:    negl %eax
+; AVX512VL-NEXT:    cmovsl %edi, %eax
+; AVX512VL-NEXT:    retq
+;
+; AVX512FP16-LABEL: abs_gpr:
+; AVX512FP16:       # %bb.0:
+; AVX512FP16-NEXT:    movl %edi, %eax
+; AVX512FP16-NEXT:    negl %eax
+; AVX512FP16-NEXT:    cmovsl %edi, %eax
+; AVX512FP16-NEXT:    retq
+  %a = call i32 @llvm.abs.i32(i32 %x, i1 false)
+  ret i32 %a
+}
+
+define i32 @abs_load_to_gpr(ptr %p) nounwind {
+; SSE2-LABEL: abs_load_to_gpr:
+; SSE2:       # %bb.0:
+; SSE2-NEXT:    movl (%rdi), %ecx
+; SSE2-NEXT:    movl %ecx, %eax
+; SSE2-NEXT:    negl %eax
+; SSE2-NEXT:    cmovsl %ecx, %eax
+; SSE2-NEXT:    retq
+;
+; SSE41-LABEL: abs_load_to_gpr:
+; SSE41:       # %bb.0:
+; SSE41-NEXT:    movl (%rdi), %ecx
+; SSE41-NEXT:    movl %ecx, %eax
+; SSE41-NEXT:    negl %eax
+; SSE41-NEXT:    cmovsl %ecx, %eax
+; SSE41-NEXT:    retq
+;
+; X86-SSE41-LABEL: abs_load_to_gpr:
+; X86-SSE41:       # %bb.0:
+; X86-SSE41-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-SSE41-NEXT:    movl (%eax), %ecx
+; X86-SSE41-NEXT:    movl %ecx, %eax
+; X86-SSE41-NEXT:    negl %eax
+; X86-SSE41-NEXT:    cmovsl %ecx, %eax
+; X86-SSE41-NEXT:    retl
+;
+; AVX-LABEL: abs_load_to_gpr:
+; AVX:       # %bb.0:
+; AVX-NEXT:    movl (%rdi), %ecx
+; AVX-NEXT:    movl %ecx, %eax
+; AVX-NEXT:    negl %eax
+; AVX-NEXT:    cmovsl %ecx, %eax
+; AVX-NEXT:    retq
+;
+; AVX512F-LABEL: abs_load_to_gpr:
+; AVX512F:       # %bb.0:
+; AVX512F-NEXT:    movl (%rdi), %ecx
+; AVX512F-NEXT:    movl %ecx, %eax
+; AVX512F-NEXT:    negl %eax
+; AVX512F-NEXT:    cmovsl %ecx, %eax
+; AVX512F-NEXT:    retq
+;
+; AVX512VL-LABEL: abs_load_to_gpr:
+; AVX512VL:       # %bb.0:
+; AVX512VL-NEXT:    movl (%rdi), %ecx
+; AVX512VL-NEXT:    movl %ecx, %eax
+; AVX512VL-NEXT:    negl %eax
+; AVX512VL-NEXT:    cmovsl %ecx, %eax
+; AVX512VL-NEXT:    retq
+;
+; AVX512FP16-LABEL: abs_load_to_gpr:
+; AVX512FP16:       # %bb.0:
+; AVX512FP16-NEXT:    movl (%rdi), %ecx
+; AVX512FP16-NEXT:    movl %ecx, %eax
+; AVX512FP16-NEXT:    negl %eax
+; AVX512FP16-NEXT:    cmovsl %ecx, %eax
+; AVX512FP16-NEXT:    retq
+  %x = load i32, ptr %p, align 4
+  %a = call i32 @llvm.abs.i32(i32 %x, i1 false)
+  ret i32 %a
+}
+
+; Negative: noimplicitfloat must not introduce XMM ops for abs.
+define void @store_abs_i32_noimplicitfloat(ptr %p, ptr %r) nounwind noimplicitfloat {
+; SSE2-LABEL: store_abs_i32_noimplicitfloat:
+; SSE2:       # %bb.0:
+; SSE2-NEXT:    movl (%rdi), %eax
+; SSE2-NEXT:    movl %eax, %ecx
+; SSE2-NEXT:    negl %ecx
+; SSE2-NEXT:    cmovsl %eax, %ecx
+; SSE2-NEXT:    movl %ecx, (%rsi)
+; SSE2-NEXT:    retq
+;
+; SSE41-LABEL: store_abs_i32_noimplicitfloat:
+; SSE41:       # %bb.0:
+; SSE41-NEXT:    movl (%rdi), %eax
+; SSE41-NEXT:    movl %eax, %ecx
+; SSE41-NEXT:    negl %ecx
+; SSE41-NEXT:    cmovsl %eax, %ecx
+; SSE41-NEXT:    movl %ecx, (%rsi)
+; SSE41-NEXT:    retq
+;
+; X86-SSE41-LABEL: store_abs_i32_noimplicitfloat:
+; X86-SSE41:       # %bb.0:
+; X86-SSE41-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-SSE41-NEXT:    movl {{[0-9]+}}(%esp), %ecx
+; X86-SSE41-NEXT:    movl (%ecx), %ecx
+; X86-SSE41-NEXT:    movl %ecx, %edx
+; X86-SSE41-NEXT:    negl %edx
+; X86-SSE41-NEXT:    cmovsl %ecx, %edx
+; X86-SSE41-NEXT:    movl %edx, (%eax)
+; X86-SSE41-NEXT:    retl
+;
+; AVX-LABEL: store_abs_i32_noimplicitfloat:
+; AVX:       # %bb.0:
+; AVX-NEXT:    movl (%rdi), %eax
+; AVX-NEXT:    movl %eax, %ecx
+; AVX-NEXT:    negl %ecx
+; AVX-NEXT:    cmovsl %eax, %ecx
+; AVX-NEXT:    movl %ecx, (%rsi)
+; AVX-NEXT:    retq
+;
+; AVX512F-LABEL: store_abs_i32_noimplicitfloat:
+; AVX512F:       # %bb.0:
+; AVX512F-NEXT:    movl (%rdi), %eax
+; AVX512F-NEXT:    movl %eax, %ecx
+; AVX512F-NEXT:    negl %ecx
+; AVX512F-NEXT:    cmovsl %eax, %ecx
+; AVX512F-NEXT:    movl %ecx, (%rsi)
+; AVX512F-NEXT:    retq
+;
+; AVX512VL-LABEL: store_abs_i32_noimplicitfloat:
+; AVX512VL:       # %bb.0:
+; AVX512VL-NEXT:    movl (%rdi), %eax
+; AVX512VL-NEXT:    movl %eax, %ecx
+; AVX512VL-NEXT:    negl %ecx
+; AVX512VL-NEXT:    cmovsl %eax, %ecx
+; AVX512VL-NEXT:    movl %ecx, (%rsi)
+; AVX512VL-NEXT:    retq
+;
+; AVX512FP16-LABEL: store_abs_i32_noimplicitfloat:
+; AVX512FP16:       # %bb.0:
+; AVX512FP16-NEXT:    movl (%rdi), %eax
+; AVX512FP16-NEXT:    movl %eax, %ecx
+; AVX512FP16-NEXT:    negl %ecx
+; AVX512FP16-NEXT:    cmovsl %eax, %ecx
+; AVX512FP16-NEXT:    movl %ecx, (%rsi)
+; AVX512FP16-NEXT:    retq
+  %x = load i32, ptr %p, align 4
+  %a = call i32 @llvm.abs.i32(i32 %x, i1 false)
+  store i32 %a, ptr %r, align 4
+  ret void
+}
+
+; Negative: optsize prefers compact neg+cmov over movd+pabsd.
+define void @store_abs_i32_optsize(ptr %p, ptr %r) nounwind optsize {
+; SSE2-LABEL: store_abs_i32_optsize:
+; SSE2:       # %bb.0:
+; SSE2-NEXT:    movl (%rdi), %eax
+; SSE2-NEXT:    movl %eax, %ecx
+; SSE2-NEXT:    negl %ecx
+; SSE2-NEXT:    cmovsl %eax, %ecx
+; SSE2-NEXT:    movl %ecx, (%rsi)
+; SSE2-NEXT:    retq
+;
+; SSE41-LABEL: store_abs_i32_optsize:
+; SSE41:       # %bb.0:
+; SSE41-NEXT:    movl (%rdi), %eax
+; SSE41-NEXT:    movl %eax, %ecx
+; SSE41-NEXT:    negl %ecx
+; SSE41-NEXT:    cmovsl %eax, %ecx
+; SSE41-NEXT:    movl %ecx, (%rsi)
+; SSE41-NEXT:    retq
+;
+; X86-SSE41-LABEL: store_abs_i32_optsize:
+; X86-SSE41:       # %bb.0:
+; X86-SSE41-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-SSE41-NEXT:    movl {{[0-9]+}}(%esp), %ecx
+; X86-SSE41-NEXT:    movl (%ecx), %ecx
+; X86-SSE41-NEXT:    movl %ecx, %edx
+; X86-SSE41-NEXT:    negl %edx
+; X86-SSE41-NEXT:    cmovsl %ecx, %edx
+; X86-SSE41-NEXT:    movl %edx, (%eax)
+; X86-SSE41-NEXT:    retl
+;
+; AVX-LABEL: store_abs_i32_optsize:
+; AVX:       # %bb.0:
+; AVX-NEXT:    movl (%rdi), %eax
+; AVX-NEXT:    movl %eax, %ecx
+; AVX-NEXT:    negl %ecx
+; AVX-NEXT:    cmovsl %eax, %ecx
+; AVX-NEXT:    movl %ecx, (%rsi)
+; AVX-NEXT:    retq
+;
+; AVX512F-LABEL: store_abs_i32_optsize:
+; AVX512F:       # %bb.0:
+; AVX512F-NEXT:    movl (%rdi), %eax
+; AVX512F-NEXT:    movl %eax, %ecx
+; AVX512F-NEXT:    negl %ecx
+; AVX512F-NEXT:    cmovsl %eax, %ecx
+; AVX512F-NEXT:    movl %ecx, (%rsi)
+; AVX512F-NEXT:    retq
+;
+; AVX512VL-LABEL: store_abs_i32_optsize:
+; AVX512VL:       # %bb.0:
+; AVX512VL-NEXT:    movl (%rdi), %eax
+; AVX512VL-NEXT:    movl %eax, %ecx
+; AVX512VL-NEXT:    negl %ecx
+; AVX512VL-NEXT:    cmovsl %eax, %ecx
+; AVX512VL-NEXT:    movl %ecx, (%rsi)
+; AVX512VL-NEXT:    retq
+;
+; AVX512FP16-LABEL: store_abs_i32_optsize:
+; AVX512FP16:       # %bb.0:
+; AVX512FP16-NEXT:    movl (%rdi), %eax
+; AVX512FP16-NEXT:    movl %eax, %ecx
+; AVX512FP16-NEXT:    negl %ecx
+; AVX512FP16-NEXT:    cmovsl %eax, %ecx
+; AVX512FP16-NEXT:    movl %ecx, (%rsi)
+; AVX512FP16-NEXT:    retq
+  %x = load i32, ptr %p, align 4
+  %a = call i32 @llvm.abs.i32(i32 %x, i1 false)
+  store i32 %a, ptr %r, align 4
+  ret void
+}
+
+; i64 needs AVX512F+VLX (movq + vpminsq/vpmaxsq/vpabsq).
+define void @sort2_i64(ptr %a) nounwind {
+; SSE2-LABEL: sort2_i64:
+; SSE2:       # %bb.0:
+; SSE2-NEXT:    movq (%rdi), %rax
+; SSE2-NEXT:    movq 8(%rdi), %rcx
+; SSE2-NEXT:    cmpq %rcx, %rax
+; SSE2-NEXT:    movq %rcx, %rdx
+; SSE2-NEXT:    cmovlq %rax, %rdx
+; SSE2-NEXT:    cmovgq %rax, %rcx
+; SSE2-NEXT:    movq %rdx, (%rdi)
+; SSE2-NEXT:    movq %rcx, 8(%rdi)
+; SSE2-NEXT:    retq
+;
+; SSE41-LABEL: sort2_i64:
+; SSE41:       # %bb.0:
+; SSE41-NEXT:    movq (%rdi), %rax
+; SSE41-NEXT:    movq 8(%rdi), %rcx
+; SSE41-NEXT:    cmpq %rcx, %rax
+; SSE41-NEXT:    movq %rcx, %rdx
+; SSE41-NEXT:    cmovlq %rax, %rdx
+; SSE41-NEXT:    cmovgq %rax, %rcx
+; SSE41-NEXT:    movq %rdx, (%rdi)
+; SSE41-NEXT:    movq %rcx, 8(%rdi)
+; SSE41-NEXT:    retq
+;
+; X86-SSE41-LABEL: sort2_i64:
+; X86-SSE41:       # %bb.0:
+; X86-SSE41-NEXT:    pushl %ebp
+; X86-SSE41-NEXT:    pushl %ebx
+; X86-SSE41-NEXT:    pushl %edi
+; X86-SSE41-NEXT:    pushl %esi
+; X86-SSE41-NEXT:    movl {{[0-9]+}}(%esp), %ecx
+; X86-SSE41-NEXT:    movl (%ecx), %edx
+; X86-SSE41-NEXT:    movl 4(%ecx), %edi
+; X86-SSE41-NEXT:    movl 12(%ecx), %eax
+; X86-SSE41-NEXT:    movl 8(%ecx), %esi
+; X86-SSE41-NEXT:    cmpl %esi, %edx
+; X86-SSE41-NEXT:    movl %edi, %ebx
+; X86-SSE41-NEXT:    sbbl %eax, %ebx
+; X86-SSE41-NEXT:    movl %eax, %ebx
+; X86-SSE41-NEXT:    cmovll %edi, %ebx
+; X86-SSE41-NEXT:    movl %esi, %ebp
+; X86-SSE41-NEXT:    cmovll %edx, %ebp
+; X86-SSE41-NEXT:    cmpl %edx, %esi
+; X86-SSE41-NEXT:    movl %eax, %ecx
+; X86-SSE41-NEXT:    sbbl %edi, %ecx
+; X86-SSE41-NEXT:    cmovll %edi, %eax
+; X86-SSE41-NEXT:    cmovll %edx, %esi
+; X86-SSE41-NEXT:    movl {{[0-9]+}}(%esp), %ecx
+; X86-SSE41-NEXT:    movl %ebp, (%ecx)
+; X86-SSE41-NEXT:    movl %ebx, 4(%ecx)
+; X86-SSE41-NEXT:    movl %esi, 8(%ecx)
+; X86-SSE41-NEXT:    movl %eax, 12(%ecx)
+; X86-SSE41-NEXT:    popl %esi
+; X86-SSE41-NEXT:    popl %edi
+; X86-SSE41-NEXT:    popl %ebx
+; X86-SSE41-NEXT:    popl %ebp
+; X86-SSE41-NEXT:    retl
+;
+; AVX-LABEL: sort2_i64:
+; AVX:       # %bb.0:
+; AVX-NEXT:    movq (%rdi), %rax
+; AVX-NEXT:    movq 8(%rdi), %rcx
+; AVX-NEXT:    cmpq %rcx, %rax
+; AVX-NEXT:    movq %rcx, %rdx
+; AVX-NEXT:    cmovlq %rax, %rdx
+; AVX-NEXT:    cmovgq %rax, %rcx
+; AVX-NEXT:    movq %rdx, (%rdi)
+; AVX-NEXT:    movq %rcx, 8(%rdi)
+; AVX-NEXT:    retq
+;
+; AVX512F-LABEL: sort2_i64:
+; AVX512F:       # %bb.0:
+; AVX512F-NEXT:    movq (%rdi), %rax
+; AVX512F-NEXT:    movq 8(%rdi), %rcx
+; AVX512F-NEXT:    cmpq %rcx, %rax
+; AVX512F-NEXT:    movq %rcx, %rdx
+; AVX512F-NEXT:    cmovlq %rax, %rdx
+; AVX512F-NEXT:    cmovgq %rax, %rcx
+; AVX512F-NEXT:    movq %rdx, (%rdi)
+; AVX512F-NEXT:    movq %rcx, 8(%rdi)
+; AVX512F-NEXT:    retq
----------------
RKSimon wrote:

This would be fine - AVX512 targets without VLX do 512-bits really well most of the time.
```
; AVX512F-LABEL: sort2_i64:
; AVX512F:       # %bb.0:
; AVX512F-NEXT:    vmovq {{.*#+}} xmm0 = mem[0],zero
; AVX512F-NEXT:    vmovq {{.*#+}} xmm1 = mem[0],zero
; AVX512F-NEXT:    vpminsq %zmm0, %zmm1, %zmm2
; AVX512F-NEXT:    vpmaxsq %zmm0, %zmm1, %zmm0
; AVX512F-NEXT:    vpunpcklqdq {{.*#+}} xmm0 = xmm2[0],xmm0[0]
; AVX512F-NEXT:    vmovdqu %xmm0, (%rdi)
; AVX512F-NEXT:    retq
```

https://github.com/llvm/llvm-project/pull/210654


More information about the llvm-commits mailing list