[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