[llvm] [X86] Convert FP compares split by a nested logic op to FP logic (PR #226222)
Tim Besard via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 28 06:52:15 PDT 2026
https://github.com/maleadt updated https://github.com/llvm/llvm-project/pull/226222
>From 9135ef7fae79124983dd7f1d49af5235719c596f Mon Sep 17 00:00:00 2001
From: Tim Besard <tim.besard at gmail.com>
Date: Thu, 24 Sep 2026 12:47:54 +0200
Subject: [PATCH 1/6] [X86] Add tests for FP compares separated by a nested
logic op (NFC)
Add coverage for chains such as
(and (and (setcc fp), (setcc int)), (setcc fp)), where the two FP
compares are not direct operands of the same logic op, so
convertIntLogicToFPLogic does not combine them as FP logic.
---
llvm/test/CodeGen/X86/fcmp-logic.ll | 187 ++++++++++++++++++++++++++++
1 file changed, 187 insertions(+)
diff --git a/llvm/test/CodeGen/X86/fcmp-logic.ll b/llvm/test/CodeGen/X86/fcmp-logic.ll
index 98fa725b2ea3a..8d35b33ff6efd 100644
--- a/llvm/test/CodeGen/X86/fcmp-logic.ll
+++ b/llvm/test/CodeGen/X86/fcmp-logic.ll
@@ -433,3 +433,190 @@ define i1 @PR140534(i32 %a0, i32 %a1, i32 %a2) {
%or = or i1 %cmp0, %cmp2
ret i1 %or
}
+
+; Two FP compares that another compare separates in a chain of logic ops.
+
+; Int64 > Float64 comparison. The olt against 2^63 becomes SETLT because
+; neither operand can be NaN, so the generic reassociation of compares with the
+; same predicate pairs it with the integer compare instead of the oeq.
+define i1 @sitofp_i64_gt_f64(i64 %x, double %y) {
+; SSE2-LABEL: sitofp_i64_gt_f64:
+; SSE2: # %bb.0:
+; SSE2-NEXT: cvtsi2sd %rdi, %xmm1
+; SSE2-NEXT: ucomisd %xmm0, %xmm1
+; SSE2-NEXT: seta %cl
+; SSE2-NEXT: ucomisd %xmm1, %xmm0
+; SSE2-NEXT: setnp %al
+; SSE2-NEXT: sete %dl
+; SSE2-NEXT: andb %al, %dl
+; SSE2-NEXT: ucomisd {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm1
+; SSE2-NEXT: setb %sil
+; SSE2-NEXT: cvttsd2si %xmm1, %rax
+; SSE2-NEXT: cmpq %rdi, %rax
+; SSE2-NEXT: setl %al
+; SSE2-NEXT: andb %dl, %al
+; SSE2-NEXT: andb %sil, %al
+; SSE2-NEXT: orb %cl, %al
+; SSE2-NEXT: retq
+;
+; AVX-LABEL: sitofp_i64_gt_f64:
+; AVX: # %bb.0:
+; AVX-NEXT: vcvtsi2sd %rdi, %xmm15, %xmm1
+; AVX-NEXT: vucomisd %xmm0, %xmm1
+; AVX-NEXT: seta %cl
+; AVX-NEXT: vucomisd %xmm1, %xmm0
+; AVX-NEXT: setnp %al
+; AVX-NEXT: sete %dl
+; AVX-NEXT: andb %al, %dl
+; AVX-NEXT: vucomisd {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm1
+; AVX-NEXT: setb %sil
+; AVX-NEXT: vcvttsd2si %xmm1, %rax
+; AVX-NEXT: cmpq %rdi, %rax
+; AVX-NEXT: setl %al
+; AVX-NEXT: andb %dl, %al
+; AVX-NEXT: andb %sil, %al
+; AVX-NEXT: orb %cl, %al
+; AVX-NEXT: retq
+ %d = sitofp i64 %x to double
+ %lt = fcmp olt double %y, %d
+ %eq = fcmp oeq double %y, %d
+ %inrange = fcmp olt double %d, 0x43E0000000000000
+ %and1 = and i1 %eq, %inrange
+ %t = fptosi double %d to i64
+ %cmp = icmp slt i64 %t, %x
+ %and2 = and i1 %and1, %cmp
+ %or = or i1 %lt, %and2
+ ret i1 %or
+}
+
+define i1 @olt_icmp_ole_or_f32(float %w, float %x, float %y, float %z, i32 %a, i32 %b) {
+; SSE2-LABEL: olt_icmp_ole_or_f32:
+; SSE2: # %bb.0:
+; SSE2-NEXT: ucomiss %xmm0, %xmm1
+; SSE2-NEXT: seta %cl
+; SSE2-NEXT: cmpl %esi, %edi
+; SSE2-NEXT: setg %al
+; SSE2-NEXT: ucomiss %xmm2, %xmm3
+; SSE2-NEXT: setae %dl
+; SSE2-NEXT: orb %cl, %al
+; SSE2-NEXT: orb %dl, %al
+; SSE2-NEXT: retq
+;
+; AVX-LABEL: olt_icmp_ole_or_f32:
+; AVX: # %bb.0:
+; AVX-NEXT: vucomiss %xmm0, %xmm1
+; AVX-NEXT: seta %cl
+; AVX-NEXT: cmpl %esi, %edi
+; AVX-NEXT: setg %al
+; AVX-NEXT: vucomiss %xmm2, %xmm3
+; AVX-NEXT: setae %dl
+; AVX-NEXT: orb %cl, %al
+; AVX-NEXT: orb %dl, %al
+; AVX-NEXT: retq
+ %f1 = fcmp olt float %w, %x
+ %i = icmp sgt i32 %a, %b
+ %f2 = fcmp ole float %y, %z
+ %or1 = or i1 %f1, %i
+ %or2 = or i1 %or1, %f2
+ ret i1 %or2
+}
+
+define i1 @icmp_olt_ole_and_f64(double %w, double %x, double %y, double %z, i32 %a, i32 %b) {
+; SSE2-LABEL: icmp_olt_ole_and_f64:
+; SSE2: # %bb.0:
+; SSE2-NEXT: cmpl %esi, %edi
+; SSE2-NEXT: setg %cl
+; SSE2-NEXT: ucomisd %xmm0, %xmm1
+; SSE2-NEXT: seta %al
+; SSE2-NEXT: ucomisd %xmm2, %xmm3
+; SSE2-NEXT: setae %dl
+; SSE2-NEXT: andb %cl, %al
+; SSE2-NEXT: andb %dl, %al
+; SSE2-NEXT: retq
+;
+; AVX-LABEL: icmp_olt_ole_and_f64:
+; AVX: # %bb.0:
+; AVX-NEXT: cmpl %esi, %edi
+; AVX-NEXT: setg %cl
+; AVX-NEXT: vucomisd %xmm0, %xmm1
+; AVX-NEXT: seta %al
+; AVX-NEXT: vucomisd %xmm2, %xmm3
+; AVX-NEXT: setae %dl
+; AVX-NEXT: andb %cl, %al
+; AVX-NEXT: andb %dl, %al
+; AVX-NEXT: retq
+ %i = icmp sgt i32 %a, %b
+ %f1 = fcmp olt double %w, %x
+ %f2 = fcmp ole double %y, %z
+ %and1 = and i1 %i, %f1
+ %and2 = and i1 %f2, %and1
+ ret i1 %and2
+}
+
+define i1 @olt_icmp_ole_xor_f64(double %w, double %x, double %y, double %z, i32 %a, i32 %b) {
+; SSE2-LABEL: olt_icmp_ole_xor_f64:
+; SSE2: # %bb.0:
+; SSE2-NEXT: ucomisd %xmm0, %xmm1
+; SSE2-NEXT: seta %cl
+; SSE2-NEXT: cmpl %esi, %edi
+; SSE2-NEXT: setg %al
+; SSE2-NEXT: ucomisd %xmm2, %xmm3
+; SSE2-NEXT: setae %dl
+; SSE2-NEXT: xorb %cl, %al
+; SSE2-NEXT: xorb %dl, %al
+; SSE2-NEXT: retq
+;
+; AVX-LABEL: olt_icmp_ole_xor_f64:
+; AVX: # %bb.0:
+; AVX-NEXT: vucomisd %xmm0, %xmm1
+; AVX-NEXT: seta %cl
+; AVX-NEXT: cmpl %esi, %edi
+; AVX-NEXT: setg %al
+; AVX-NEXT: vucomisd %xmm2, %xmm3
+; AVX-NEXT: setae %dl
+; AVX-NEXT: xorb %cl, %al
+; AVX-NEXT: xorb %dl, %al
+; AVX-NEXT: retq
+ %f1 = fcmp olt double %w, %x
+ %i = icmp sgt i32 %a, %b
+ %f2 = fcmp ole double %y, %z
+ %xor1 = xor i1 %f1, %i
+ %xor2 = xor i1 %xor1, %f2
+ ret i1 %xor2
+}
+
+; Negative test: the inner logic op has another use.
+define i1 @olt_icmp_ole_and_f64_use(double %w, double %x, double %y, double %z, i32 %a, i32 %b, ptr %p) {
+; SSE2-LABEL: olt_icmp_ole_and_f64_use:
+; SSE2: # %bb.0:
+; SSE2-NEXT: ucomisd %xmm0, %xmm1
+; SSE2-NEXT: seta %cl
+; SSE2-NEXT: cmpl %esi, %edi
+; SSE2-NEXT: setg %al
+; SSE2-NEXT: ucomisd %xmm2, %xmm3
+; SSE2-NEXT: setae %sil
+; SSE2-NEXT: andb %cl, %al
+; SSE2-NEXT: movb %al, (%rdx)
+; SSE2-NEXT: andb %sil, %al
+; SSE2-NEXT: retq
+;
+; AVX-LABEL: olt_icmp_ole_and_f64_use:
+; AVX: # %bb.0:
+; AVX-NEXT: vucomisd %xmm0, %xmm1
+; AVX-NEXT: seta %cl
+; AVX-NEXT: cmpl %esi, %edi
+; AVX-NEXT: setg %al
+; AVX-NEXT: vucomisd %xmm2, %xmm3
+; AVX-NEXT: setae %sil
+; AVX-NEXT: andb %cl, %al
+; AVX-NEXT: movb %al, (%rdx)
+; AVX-NEXT: andb %sil, %al
+; AVX-NEXT: retq
+ %f1 = fcmp olt double %w, %x
+ %i = icmp sgt i32 %a, %b
+ %f2 = fcmp ole double %y, %z
+ %and1 = and i1 %f1, %i
+ store i1 %and1, ptr %p
+ %and2 = and i1 %and1, %f2
+ ret i1 %and2
+}
>From 308fcf339b0a392f9ea0b9dc579221512fc710f2 Mon Sep 17 00:00:00 2001
From: Tim Besard <tim.besard at gmail.com>
Date: Thu, 24 Sep 2026 13:03:14 +0200
Subject: [PATCH 2/6] [X86] Convert FP compares split by a nested logic op to
FP logic
convertIntLogicToFPLogic turns a logic op of two scalar FP compares into
CMPSS/CMPSD and FP logic, avoiding COMIS/SETcc sequences. It only looks
at the direct operands, so it misses chains such as
(and (and (setcc fp), (setcc int)), (setcc fp))
Since #169904, SelectionDAGBuilder gives FP compares whose operands are
known never NaN the same condition code as integer compares (e.g.
SETLT for `fcmp olt (sitofp x), 2^63`). DAGCombiner's reassociation of
compares with the same predicate then pairs such an FP compare with an
integer compare and separates it from the other FP compare. This hits
the exact `Int64 > Float64` comparison as emitted by Julia:
(or (setcc olt y, d),
(and (and (setcc oeq y, d), (setcc lt d, 2^63)),
(setcc lt (fp_to_sint d), x)))
which went from cmpeqsd/cmpltsd/andpd to three ucomisd with SETcc
chains.
For i1 logic, look through one level of a single-use inner logic op of
the same kind and pair its FP compare with the outer one:
(logic (logic (setcc fp), (setcc fp)), rest). The generic reassociation
is left alone, as other targets benefit from pairing the FP compare
with the integer one (e.g. AArch64 forms FCMP + CCMP for it). The
converted pair is no longer a SETCC, so the reassociation cannot undo
the transform.
Assisted-by: Claude Code, Codex
---
llvm/lib/Target/X86/X86ISelLowering.cpp | 25 ++-
llvm/test/CodeGen/X86/fcmp-logic.ll | 201 +++++++++++++++---------
2 files changed, 149 insertions(+), 77 deletions(-)
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 6dc7126834beb..6a736e7bc8a77 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -52660,7 +52660,9 @@ static unsigned convertIntLogicToFPLogicOpcode(unsigned Opcode) {
/// If both input operands of a logic op are being cast from floating-point
/// types or FP compares, try to convert this into a floating-point logic node
-/// to avoid unnecessary moves from SSE to integer registers.
+/// to avoid unnecessary moves from SSE to integer registers. For i1 logic, also
+/// look through one level of a nested logic op of the same kind to pair up two
+/// FP compares.
static SDValue convertIntLogicToFPLogic(unsigned Opc, const SDLoc &DL, EVT VT,
SDValue N0, SDValue N1,
SelectionDAG &DAG,
@@ -52669,6 +52671,27 @@ static SDValue convertIntLogicToFPLogic(unsigned Opc, const SDLoc &DL, EVT VT,
assert((Opc == ISD::OR || Opc == ISD::AND || Opc == ISD::XOR) &&
"Unexpected bit opcode");
+ // Look through a single-use inner logic op to pair up two FP compares that
+ // it separates, e.g. by an integer compare. The recursive call only sees
+ // SETCC operands, so this is limited to one level:
+ // logic (logic (setcc X), Y), (setcc Z) -->
+ // logic (logic (setcc X), (setcc Z)), Y
+ if (VT == MVT::i1) {
+ if (N1.getOpcode() == Opc)
+ std::swap(N0, N1);
+ if (N0.getOpcode() == Opc && N0.hasOneUse() &&
+ N1.getOpcode() == ISD::SETCC) {
+ for (unsigned I = 0; I != 2; ++I) {
+ SDValue Cmp = N0.getOperand(I);
+ if (Cmp.getOpcode() != ISD::SETCC)
+ continue;
+ if (SDValue FPLogic = convertIntLogicToFPLogic(Opc, DL, VT, Cmp, N1,
+ DAG, DCI, Subtarget))
+ return DAG.getNode(Opc, DL, VT, FPLogic, N0.getOperand(1 - I));
+ }
+ }
+ }
+
if (!((N0.getOpcode() == ISD::BITCAST && N1.getOpcode() == ISD::BITCAST) ||
(N0.getOpcode() == ISD::SETCC && N1.getOpcode() == ISD::SETCC)))
return SDValue();
diff --git a/llvm/test/CodeGen/X86/fcmp-logic.ll b/llvm/test/CodeGen/X86/fcmp-logic.ll
index 8d35b33ff6efd..e0538f545ff93 100644
--- a/llvm/test/CodeGen/X86/fcmp-logic.ll
+++ b/llvm/test/CodeGen/X86/fcmp-logic.ll
@@ -445,38 +445,51 @@ define i1 @sitofp_i64_gt_f64(i64 %x, double %y) {
; SSE2-NEXT: cvtsi2sd %rdi, %xmm1
; SSE2-NEXT: ucomisd %xmm0, %xmm1
; SSE2-NEXT: seta %cl
-; SSE2-NEXT: ucomisd %xmm1, %xmm0
-; SSE2-NEXT: setnp %al
-; SSE2-NEXT: sete %dl
-; SSE2-NEXT: andb %al, %dl
-; SSE2-NEXT: ucomisd {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm1
-; SSE2-NEXT: setb %sil
; SSE2-NEXT: cvttsd2si %xmm1, %rax
; SSE2-NEXT: cmpq %rdi, %rax
-; SSE2-NEXT: setl %al
+; SSE2-NEXT: setl %dl
+; SSE2-NEXT: cmpeqsd %xmm1, %xmm0
+; SSE2-NEXT: cmpltsd {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm1
+; SSE2-NEXT: andpd %xmm0, %xmm1
+; SSE2-NEXT: movd %xmm1, %eax
; SSE2-NEXT: andb %dl, %al
-; SSE2-NEXT: andb %sil, %al
; SSE2-NEXT: orb %cl, %al
+; SSE2-NEXT: # kill: def $al killed $al killed $eax
; SSE2-NEXT: retq
;
-; AVX-LABEL: sitofp_i64_gt_f64:
-; AVX: # %bb.0:
-; AVX-NEXT: vcvtsi2sd %rdi, %xmm15, %xmm1
-; AVX-NEXT: vucomisd %xmm0, %xmm1
-; AVX-NEXT: seta %cl
-; AVX-NEXT: vucomisd %xmm1, %xmm0
-; AVX-NEXT: setnp %al
-; AVX-NEXT: sete %dl
-; AVX-NEXT: andb %al, %dl
-; AVX-NEXT: vucomisd {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm1
-; AVX-NEXT: setb %sil
-; AVX-NEXT: vcvttsd2si %xmm1, %rax
-; AVX-NEXT: cmpq %rdi, %rax
-; AVX-NEXT: setl %al
-; AVX-NEXT: andb %dl, %al
-; AVX-NEXT: andb %sil, %al
-; AVX-NEXT: orb %cl, %al
-; AVX-NEXT: retq
+; AVX1-LABEL: sitofp_i64_gt_f64:
+; AVX1: # %bb.0:
+; AVX1-NEXT: vcvtsi2sd %rdi, %xmm15, %xmm1
+; AVX1-NEXT: vucomisd %xmm0, %xmm1
+; AVX1-NEXT: seta %cl
+; AVX1-NEXT: vcvttsd2si %xmm1, %rax
+; AVX1-NEXT: cmpq %rdi, %rax
+; AVX1-NEXT: setl %dl
+; AVX1-NEXT: vcmpeqsd %xmm1, %xmm0, %xmm0
+; AVX1-NEXT: vcmpltsd {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm1, %xmm1
+; AVX1-NEXT: vandpd %xmm0, %xmm1, %xmm0
+; AVX1-NEXT: vmovd %xmm0, %eax
+; AVX1-NEXT: andb %dl, %al
+; AVX1-NEXT: orb %cl, %al
+; AVX1-NEXT: # kill: def $al killed $al killed $eax
+; AVX1-NEXT: retq
+;
+; AVX512-LABEL: sitofp_i64_gt_f64:
+; AVX512: # %bb.0:
+; AVX512-NEXT: vcvtsi2sd %rdi, %xmm15, %xmm1
+; AVX512-NEXT: vucomisd %xmm0, %xmm1
+; AVX512-NEXT: seta %cl
+; AVX512-NEXT: vcvttsd2si %xmm1, %rax
+; AVX512-NEXT: cmpq %rdi, %rax
+; AVX512-NEXT: setl %dl
+; AVX512-NEXT: vcmpeqsd %xmm1, %xmm0, %k0
+; AVX512-NEXT: vcmpltsd {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm1, %k1
+; AVX512-NEXT: kandw %k0, %k1, %k0
+; AVX512-NEXT: kmovw %k0, %eax
+; AVX512-NEXT: andb %dl, %al
+; AVX512-NEXT: orb %cl, %al
+; AVX512-NEXT: # kill: def $al killed $al killed $eax
+; AVX512-NEXT: retq
%d = sitofp i64 %x to double
%lt = fcmp olt double %y, %d
%eq = fcmp oeq double %y, %d
@@ -492,27 +505,39 @@ define i1 @sitofp_i64_gt_f64(i64 %x, double %y) {
define i1 @olt_icmp_ole_or_f32(float %w, float %x, float %y, float %z, i32 %a, i32 %b) {
; SSE2-LABEL: olt_icmp_ole_or_f32:
; SSE2: # %bb.0:
-; SSE2-NEXT: ucomiss %xmm0, %xmm1
-; SSE2-NEXT: seta %cl
; SSE2-NEXT: cmpl %esi, %edi
-; SSE2-NEXT: setg %al
-; SSE2-NEXT: ucomiss %xmm2, %xmm3
-; SSE2-NEXT: setae %dl
+; SSE2-NEXT: setg %cl
+; SSE2-NEXT: cmpless %xmm3, %xmm2
+; SSE2-NEXT: cmpltss %xmm1, %xmm0
+; SSE2-NEXT: orps %xmm2, %xmm0
+; SSE2-NEXT: movd %xmm0, %eax
; SSE2-NEXT: orb %cl, %al
-; SSE2-NEXT: orb %dl, %al
+; SSE2-NEXT: # kill: def $al killed $al killed $eax
; SSE2-NEXT: retq
;
-; AVX-LABEL: olt_icmp_ole_or_f32:
-; AVX: # %bb.0:
-; AVX-NEXT: vucomiss %xmm0, %xmm1
-; AVX-NEXT: seta %cl
-; AVX-NEXT: cmpl %esi, %edi
-; AVX-NEXT: setg %al
-; AVX-NEXT: vucomiss %xmm2, %xmm3
-; AVX-NEXT: setae %dl
-; AVX-NEXT: orb %cl, %al
-; AVX-NEXT: orb %dl, %al
-; AVX-NEXT: retq
+; AVX1-LABEL: olt_icmp_ole_or_f32:
+; AVX1: # %bb.0:
+; AVX1-NEXT: cmpl %esi, %edi
+; AVX1-NEXT: setg %cl
+; AVX1-NEXT: vcmpless %xmm3, %xmm2, %xmm2
+; AVX1-NEXT: vcmpltss %xmm1, %xmm0, %xmm0
+; AVX1-NEXT: vorps %xmm2, %xmm0, %xmm0
+; AVX1-NEXT: vmovd %xmm0, %eax
+; AVX1-NEXT: orb %cl, %al
+; AVX1-NEXT: # kill: def $al killed $al killed $eax
+; AVX1-NEXT: retq
+;
+; AVX512-LABEL: olt_icmp_ole_or_f32:
+; AVX512: # %bb.0:
+; AVX512-NEXT: cmpl %esi, %edi
+; AVX512-NEXT: setg %cl
+; AVX512-NEXT: vcmpless %xmm3, %xmm2, %k0
+; AVX512-NEXT: vcmpltss %xmm1, %xmm0, %k1
+; AVX512-NEXT: korw %k0, %k1, %k0
+; AVX512-NEXT: kmovw %k0, %eax
+; AVX512-NEXT: orb %cl, %al
+; AVX512-NEXT: # kill: def $al killed $al killed $eax
+; AVX512-NEXT: retq
%f1 = fcmp olt float %w, %x
%i = icmp sgt i32 %a, %b
%f2 = fcmp ole float %y, %z
@@ -526,25 +551,37 @@ define i1 @icmp_olt_ole_and_f64(double %w, double %x, double %y, double %z, i32
; SSE2: # %bb.0:
; SSE2-NEXT: cmpl %esi, %edi
; SSE2-NEXT: setg %cl
-; SSE2-NEXT: ucomisd %xmm0, %xmm1
-; SSE2-NEXT: seta %al
-; SSE2-NEXT: ucomisd %xmm2, %xmm3
-; SSE2-NEXT: setae %dl
+; SSE2-NEXT: cmplesd %xmm3, %xmm2
+; SSE2-NEXT: cmpltsd %xmm1, %xmm0
+; SSE2-NEXT: andpd %xmm2, %xmm0
+; SSE2-NEXT: movd %xmm0, %eax
; SSE2-NEXT: andb %cl, %al
-; SSE2-NEXT: andb %dl, %al
+; SSE2-NEXT: # kill: def $al killed $al killed $eax
; SSE2-NEXT: retq
;
-; AVX-LABEL: icmp_olt_ole_and_f64:
-; AVX: # %bb.0:
-; AVX-NEXT: cmpl %esi, %edi
-; AVX-NEXT: setg %cl
-; AVX-NEXT: vucomisd %xmm0, %xmm1
-; AVX-NEXT: seta %al
-; AVX-NEXT: vucomisd %xmm2, %xmm3
-; AVX-NEXT: setae %dl
-; AVX-NEXT: andb %cl, %al
-; AVX-NEXT: andb %dl, %al
-; AVX-NEXT: retq
+; AVX1-LABEL: icmp_olt_ole_and_f64:
+; AVX1: # %bb.0:
+; AVX1-NEXT: cmpl %esi, %edi
+; AVX1-NEXT: setg %cl
+; AVX1-NEXT: vcmplesd %xmm3, %xmm2, %xmm2
+; AVX1-NEXT: vcmpltsd %xmm1, %xmm0, %xmm0
+; AVX1-NEXT: vandpd %xmm2, %xmm0, %xmm0
+; AVX1-NEXT: vmovd %xmm0, %eax
+; AVX1-NEXT: andb %cl, %al
+; AVX1-NEXT: # kill: def $al killed $al killed $eax
+; AVX1-NEXT: retq
+;
+; AVX512-LABEL: icmp_olt_ole_and_f64:
+; AVX512: # %bb.0:
+; AVX512-NEXT: cmpl %esi, %edi
+; AVX512-NEXT: setg %cl
+; AVX512-NEXT: vcmplesd %xmm3, %xmm2, %k0
+; AVX512-NEXT: vcmpltsd %xmm1, %xmm0, %k1
+; AVX512-NEXT: kandw %k0, %k1, %k0
+; AVX512-NEXT: kmovw %k0, %eax
+; AVX512-NEXT: andb %cl, %al
+; AVX512-NEXT: # kill: def $al killed $al killed $eax
+; AVX512-NEXT: retq
%i = icmp sgt i32 %a, %b
%f1 = fcmp olt double %w, %x
%f2 = fcmp ole double %y, %z
@@ -556,27 +593,39 @@ define i1 @icmp_olt_ole_and_f64(double %w, double %x, double %y, double %z, i32
define i1 @olt_icmp_ole_xor_f64(double %w, double %x, double %y, double %z, i32 %a, i32 %b) {
; SSE2-LABEL: olt_icmp_ole_xor_f64:
; SSE2: # %bb.0:
-; SSE2-NEXT: ucomisd %xmm0, %xmm1
-; SSE2-NEXT: seta %cl
; SSE2-NEXT: cmpl %esi, %edi
-; SSE2-NEXT: setg %al
-; SSE2-NEXT: ucomisd %xmm2, %xmm3
-; SSE2-NEXT: setae %dl
+; SSE2-NEXT: setg %cl
+; SSE2-NEXT: cmplesd %xmm3, %xmm2
+; SSE2-NEXT: cmpltsd %xmm1, %xmm0
+; SSE2-NEXT: xorpd %xmm2, %xmm0
+; SSE2-NEXT: movd %xmm0, %eax
; SSE2-NEXT: xorb %cl, %al
-; SSE2-NEXT: xorb %dl, %al
+; SSE2-NEXT: # kill: def $al killed $al killed $eax
; SSE2-NEXT: retq
;
-; AVX-LABEL: olt_icmp_ole_xor_f64:
-; AVX: # %bb.0:
-; AVX-NEXT: vucomisd %xmm0, %xmm1
-; AVX-NEXT: seta %cl
-; AVX-NEXT: cmpl %esi, %edi
-; AVX-NEXT: setg %al
-; AVX-NEXT: vucomisd %xmm2, %xmm3
-; AVX-NEXT: setae %dl
-; AVX-NEXT: xorb %cl, %al
-; AVX-NEXT: xorb %dl, %al
-; AVX-NEXT: retq
+; AVX1-LABEL: olt_icmp_ole_xor_f64:
+; AVX1: # %bb.0:
+; AVX1-NEXT: cmpl %esi, %edi
+; AVX1-NEXT: setg %cl
+; AVX1-NEXT: vcmplesd %xmm3, %xmm2, %xmm2
+; AVX1-NEXT: vcmpltsd %xmm1, %xmm0, %xmm0
+; AVX1-NEXT: vxorpd %xmm2, %xmm0, %xmm0
+; AVX1-NEXT: vmovd %xmm0, %eax
+; AVX1-NEXT: xorb %cl, %al
+; AVX1-NEXT: # kill: def $al killed $al killed $eax
+; AVX1-NEXT: retq
+;
+; AVX512-LABEL: olt_icmp_ole_xor_f64:
+; AVX512: # %bb.0:
+; AVX512-NEXT: cmpl %esi, %edi
+; AVX512-NEXT: setg %cl
+; AVX512-NEXT: vcmplesd %xmm3, %xmm2, %k0
+; AVX512-NEXT: vcmpltsd %xmm1, %xmm0, %k1
+; AVX512-NEXT: kxorw %k0, %k1, %k0
+; AVX512-NEXT: kmovw %k0, %eax
+; AVX512-NEXT: xorb %cl, %al
+; AVX512-NEXT: # kill: def $al killed $al killed $eax
+; AVX512-NEXT: retq
%f1 = fcmp olt double %w, %x
%i = icmp sgt i32 %a, %b
%f2 = fcmp ole double %y, %z
>From 4d3e50d86629f4ee7be21dc5831b272a25cb9b39 Mon Sep 17 00:00:00 2001
From: Tim Besard <tim.besard at gmail.com>
Date: Thu, 24 Sep 2026 20:54:05 +0200
Subject: [PATCH 3/6] [X86] Use SDPatternMatch for the nested FP compare
look-through
Address review feedback: match the inner logic op and the FP compares with
SDPatternMatch instead of manually commuting operands.
---
llvm/lib/Target/X86/X86ISelLowering.cpp | 26 +++++++++++--------------
1 file changed, 11 insertions(+), 15 deletions(-)
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 6a736e7bc8a77..fe5af112e9eba 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -52676,21 +52676,17 @@ static SDValue convertIntLogicToFPLogic(unsigned Opc, const SDLoc &DL, EVT VT,
// SETCC operands, so this is limited to one level:
// logic (logic (setcc X), Y), (setcc Z) -->
// logic (logic (setcc X), (setcc Z)), Y
- if (VT == MVT::i1) {
- if (N1.getOpcode() == Opc)
- std::swap(N0, N1);
- if (N0.getOpcode() == Opc && N0.hasOneUse() &&
- N1.getOpcode() == ISD::SETCC) {
- for (unsigned I = 0; I != 2; ++I) {
- SDValue Cmp = N0.getOperand(I);
- if (Cmp.getOpcode() != ISD::SETCC)
- continue;
- if (SDValue FPLogic = convertIntLogicToFPLogic(Opc, DL, VT, Cmp, N1,
- DAG, DCI, Subtarget))
- return DAG.getNode(Opc, DL, VT, FPLogic, N0.getOperand(1 - I));
- }
- }
- }
+ using namespace SDPatternMatch;
+ auto FPSetCC = [](SDValue &Cmp) {
+ return m_Value(Cmp, m_SetCC(m_FloatingPointVT(), m_Value(), m_Value()));
+ };
+ SDValue X, Y, Z;
+ auto Inner = m_OneUse(m_c_BinOp(Opc, FPSetCC(X), m_Value(Y)));
+ if (VT == MVT::i1 && ((sd_match(N0, Inner) && sd_match(N1, FPSetCC(Z))) ||
+ (sd_match(N1, Inner) && sd_match(N0, FPSetCC(Z)))))
+ if (SDValue FPLogic =
+ convertIntLogicToFPLogic(Opc, DL, VT, X, Z, DAG, DCI, Subtarget))
+ return DAG.getNode(Opc, DL, VT, FPLogic, Y);
if (!((N0.getOpcode() == ISD::BITCAST && N1.getOpcode() == ISD::BITCAST) ||
(N0.getOpcode() == ISD::SETCC && N1.getOpcode() == ISD::SETCC)))
>From ad011bf07e5b064744dd08ab3e4bb327bda83e76 Mon Sep 17 00:00:00 2001
From: Tim Besard <tim.besard at gmail.com>
Date: Thu, 24 Sep 2026 21:17:44 +0200
Subject: [PATCH 4/6] [X86] Add tests for chains of more than two FP compares
(NFC)
Add the chains from #219468 plus XOR, ten-compare and near-depth-limit
chains, integer compares in the middle of FP compare chains, merges of
converted pairs, and negative tests for mixed FP types, a converted pair
with another use and vector logic that does not come from scalar FP
compares. Add f16 chains with and without AVX512VL.
---
llvm/test/CodeGen/X86/fcmp-logic-fp16.ll | 93 +++
llvm/test/CodeGen/X86/fcmp-logic.ll | 922 +++++++++++++++++++++++
2 files changed, 1015 insertions(+)
create mode 100644 llvm/test/CodeGen/X86/fcmp-logic-fp16.ll
diff --git a/llvm/test/CodeGen/X86/fcmp-logic-fp16.ll b/llvm/test/CodeGen/X86/fcmp-logic-fp16.ll
new file mode 100644
index 0000000000000..35ea845d27497
--- /dev/null
+++ b/llvm/test/CodeGen/X86/fcmp-logic-fp16.ll
@@ -0,0 +1,93 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc < %s -mtriple=x86_64-- -mattr=avx512fp16 | FileCheck %s --check-prefixes=CHECK,NOVL
+; RUN: llc < %s -mtriple=x86_64-- -mattr=avx512fp16,avx512vl | FileCheck %s --check-prefixes=CHECK,VL
+
+define i1 @olt_ole_and_f16(half %w, half %x, half %y, half %z) {
+; NOVL-LABEL: olt_ole_and_f16:
+; NOVL: # %bb.0:
+; NOVL-NEXT: vucomish %xmm2, %xmm3
+; NOVL-NEXT: setae %al
+; NOVL-NEXT: kmovd %eax, %k0
+; NOVL-NEXT: vucomish %xmm0, %xmm1
+; NOVL-NEXT: seta %al
+; NOVL-NEXT: kmovd %eax, %k1
+; NOVL-NEXT: kandw %k0, %k1, %k0
+; NOVL-NEXT: kmovd %k0, %eax
+; NOVL-NEXT: # kill: def $al killed $al killed $eax
+; NOVL-NEXT: retq
+;
+; VL-LABEL: olt_ole_and_f16:
+; VL: # %bb.0:
+; VL-NEXT: vcmplesh %xmm3, %xmm2, %k0
+; VL-NEXT: vcmpltsh %xmm1, %xmm0, %k1
+; VL-NEXT: kandw %k0, %k1, %k0
+; VL-NEXT: kmovd %k0, %eax
+; VL-NEXT: # kill: def $al killed $al killed $eax
+; VL-NEXT: retq
+ %f1 = fcmp olt half %w, %x
+ %f2 = fcmp ole half %y, %z
+ %and = and i1 %f1, %f2
+ ret i1 %and
+}
+
+define i1 @mixed_and5_f16(half %a, half %b, half %c, half %d, half %e, half %f) {
+; NOVL-LABEL: mixed_and5_f16:
+; NOVL: # %bb.0:
+; NOVL-NEXT: vucomish %xmm0, %xmm2
+; NOVL-NEXT: seta %al
+; NOVL-NEXT: xorl %ecx, %ecx
+; NOVL-NEXT: vucomish %xmm3, %xmm0
+; NOVL-NEXT: movl $255, %edx
+; NOVL-NEXT: movl $255, %esi
+; NOVL-NEXT: cmovnel %ecx, %esi
+; NOVL-NEXT: cmovpl %ecx, %esi
+; NOVL-NEXT: kmovd %esi, %k0
+; NOVL-NEXT: vucomish %xmm1, %xmm0
+; NOVL-NEXT: seta %cl
+; NOVL-NEXT: kmovd %ecx, %k1
+; NOVL-NEXT: kandw %k0, %k1, %k0
+; NOVL-NEXT: kmovd %k0, %ecx
+; NOVL-NEXT: andb %al, %cl
+; NOVL-NEXT: xorl %eax, %eax
+; NOVL-NEXT: vucomish %xmm4, %xmm0
+; NOVL-NEXT: setne %al
+; NOVL-NEXT: cmovpl %edx, %eax
+; NOVL-NEXT: kmovd %eax, %k0
+; NOVL-NEXT: vucomish %xmm5, %xmm0
+; NOVL-NEXT: setae %al
+; NOVL-NEXT: kmovd %eax, %k1
+; NOVL-NEXT: kandw %k1, %k0, %k0
+; NOVL-NEXT: kmovd %k0, %eax
+; NOVL-NEXT: andb %cl, %al
+; NOVL-NEXT: # kill: def $al killed $al killed $eax
+; NOVL-NEXT: retq
+;
+; VL-LABEL: mixed_and5_f16:
+; VL: # %bb.0:
+; VL-NEXT: vucomish %xmm0, %xmm2
+; VL-NEXT: seta %al
+; VL-NEXT: vcmpeqsh %xmm3, %xmm0, %k0
+; VL-NEXT: vcmpltsh %xmm0, %xmm1, %k1
+; VL-NEXT: kandw %k0, %k1, %k0
+; VL-NEXT: kmovd %k0, %ecx
+; VL-NEXT: andb %al, %cl
+; VL-NEXT: vcmplesh %xmm0, %xmm5, %k0
+; VL-NEXT: vcmpneqsh %xmm4, %xmm0, %k1
+; VL-NEXT: kandw %k0, %k1, %k0
+; VL-NEXT: kmovd %k0, %eax
+; VL-NEXT: andb %cl, %al
+; VL-NEXT: # kill: def $al killed $al killed $eax
+; VL-NEXT: retq
+ %c1 = fcmp ogt half %a, %b
+ %c2 = fcmp olt half %a, %c
+ %c3 = fcmp oeq half %a, %d
+ %c4 = fcmp une half %a, %e
+ %c5 = fcmp oge half %a, %f
+ %and1 = and i1 %c1, %c2
+ %and2 = and i1 %and1, %c3
+ %and3 = and i1 %and2, %c4
+ %and4 = and i1 %and3, %c5
+ ret i1 %and4
+}
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK: {{.*}}
diff --git a/llvm/test/CodeGen/X86/fcmp-logic.ll b/llvm/test/CodeGen/X86/fcmp-logic.ll
index e0538f545ff93..2b85f3882b704 100644
--- a/llvm/test/CodeGen/X86/fcmp-logic.ll
+++ b/llvm/test/CodeGen/X86/fcmp-logic.ll
@@ -669,3 +669,925 @@ define i1 @olt_icmp_ole_and_f64_use(double %w, double %x, double %y, double %z,
%and2 = and i1 %and1, %f2
ret i1 %and2
}
+
+; Chains of more than two FP compares (PR219468).
+
+define i1 @ogt_and5_f32(float %a, float %b, float %c, float %d, float %e, float %f) {
+; SSE2-LABEL: ogt_and5_f32:
+; SSE2: # %bb.0:
+; SSE2-NEXT: ucomiss %xmm2, %xmm0
+; SSE2-NEXT: seta %al
+; SSE2-NEXT: cmpltss %xmm0, %xmm3
+; SSE2-NEXT: cmpltss %xmm0, %xmm1
+; SSE2-NEXT: andps %xmm3, %xmm1
+; SSE2-NEXT: movd %xmm1, %ecx
+; SSE2-NEXT: andb %al, %cl
+; SSE2-NEXT: cmpltss %xmm0, %xmm5
+; SSE2-NEXT: cmpltss %xmm0, %xmm4
+; SSE2-NEXT: andps %xmm5, %xmm4
+; SSE2-NEXT: movd %xmm4, %eax
+; SSE2-NEXT: andb %cl, %al
+; SSE2-NEXT: # kill: def $al killed $al killed $eax
+; SSE2-NEXT: retq
+;
+; AVX1-LABEL: ogt_and5_f32:
+; AVX1: # %bb.0:
+; AVX1-NEXT: vucomiss %xmm2, %xmm0
+; AVX1-NEXT: seta %al
+; AVX1-NEXT: vcmpltss %xmm0, %xmm3, %xmm2
+; AVX1-NEXT: vcmpltss %xmm0, %xmm1, %xmm1
+; AVX1-NEXT: vandps %xmm2, %xmm1, %xmm1
+; AVX1-NEXT: vmovd %xmm1, %ecx
+; AVX1-NEXT: andb %al, %cl
+; AVX1-NEXT: vcmpltss %xmm0, %xmm5, %xmm1
+; AVX1-NEXT: vcmpltss %xmm0, %xmm4, %xmm0
+; AVX1-NEXT: vandps %xmm1, %xmm0, %xmm0
+; AVX1-NEXT: vmovd %xmm0, %eax
+; AVX1-NEXT: andb %cl, %al
+; AVX1-NEXT: # kill: def $al killed $al killed $eax
+; AVX1-NEXT: retq
+;
+; AVX512-LABEL: ogt_and5_f32:
+; AVX512: # %bb.0:
+; AVX512-NEXT: vucomiss %xmm2, %xmm0
+; AVX512-NEXT: seta %al
+; AVX512-NEXT: vcmpltss %xmm0, %xmm3, %k0
+; AVX512-NEXT: vcmpltss %xmm0, %xmm1, %k1
+; AVX512-NEXT: kandw %k0, %k1, %k0
+; AVX512-NEXT: kmovw %k0, %ecx
+; AVX512-NEXT: andb %al, %cl
+; AVX512-NEXT: vcmpltss %xmm0, %xmm5, %k0
+; AVX512-NEXT: vcmpltss %xmm0, %xmm4, %k1
+; AVX512-NEXT: kandw %k0, %k1, %k0
+; AVX512-NEXT: kmovw %k0, %eax
+; AVX512-NEXT: andb %cl, %al
+; AVX512-NEXT: # kill: def $al killed $al killed $eax
+; AVX512-NEXT: retq
+ %c1 = fcmp ogt float %a, %b
+ %c2 = fcmp ogt float %a, %c
+ %c3 = fcmp ogt float %a, %d
+ %c4 = fcmp ogt float %a, %e
+ %c5 = fcmp ogt float %a, %f
+ %and1 = and i1 %c1, %c2
+ %and2 = and i1 %and1, %c3
+ %and3 = and i1 %and2, %c4
+ %and4 = and i1 %and3, %c5
+ ret i1 %and4
+}
+
+define i1 @mixed_and5_f32(float %a, float %b, float %c, float %d, float %e, float %f) {
+; SSE2-LABEL: mixed_and5_f32:
+; SSE2: # %bb.0:
+; SSE2-NEXT: ucomiss %xmm0, %xmm2
+; SSE2-NEXT: seta %al
+; SSE2-NEXT: cmpeqss %xmm0, %xmm3
+; SSE2-NEXT: cmpltss %xmm0, %xmm1
+; SSE2-NEXT: andps %xmm3, %xmm1
+; SSE2-NEXT: movd %xmm1, %ecx
+; SSE2-NEXT: andb %al, %cl
+; SSE2-NEXT: cmpless %xmm0, %xmm5
+; SSE2-NEXT: cmpneqss %xmm0, %xmm4
+; SSE2-NEXT: andps %xmm5, %xmm4
+; SSE2-NEXT: movd %xmm4, %eax
+; SSE2-NEXT: andb %cl, %al
+; SSE2-NEXT: # kill: def $al killed $al killed $eax
+; SSE2-NEXT: retq
+;
+; AVX1-LABEL: mixed_and5_f32:
+; AVX1: # %bb.0:
+; AVX1-NEXT: vucomiss %xmm0, %xmm2
+; AVX1-NEXT: seta %al
+; AVX1-NEXT: vcmpeqss %xmm3, %xmm0, %xmm2
+; AVX1-NEXT: vcmpltss %xmm0, %xmm1, %xmm1
+; AVX1-NEXT: vandps %xmm2, %xmm1, %xmm1
+; AVX1-NEXT: vmovd %xmm1, %ecx
+; AVX1-NEXT: andb %al, %cl
+; AVX1-NEXT: vcmpless %xmm0, %xmm5, %xmm1
+; AVX1-NEXT: vcmpneqss %xmm4, %xmm0, %xmm0
+; AVX1-NEXT: vandps %xmm1, %xmm0, %xmm0
+; AVX1-NEXT: vmovd %xmm0, %eax
+; AVX1-NEXT: andb %cl, %al
+; AVX1-NEXT: # kill: def $al killed $al killed $eax
+; AVX1-NEXT: retq
+;
+; AVX512-LABEL: mixed_and5_f32:
+; AVX512: # %bb.0:
+; AVX512-NEXT: vucomiss %xmm0, %xmm2
+; AVX512-NEXT: seta %al
+; AVX512-NEXT: vcmpeqss %xmm3, %xmm0, %k0
+; AVX512-NEXT: vcmpltss %xmm0, %xmm1, %k1
+; AVX512-NEXT: kandw %k0, %k1, %k0
+; AVX512-NEXT: kmovw %k0, %ecx
+; AVX512-NEXT: andb %al, %cl
+; AVX512-NEXT: vcmpless %xmm0, %xmm5, %k0
+; AVX512-NEXT: vcmpneqss %xmm4, %xmm0, %k1
+; AVX512-NEXT: kandw %k0, %k1, %k0
+; AVX512-NEXT: kmovw %k0, %eax
+; AVX512-NEXT: andb %cl, %al
+; AVX512-NEXT: # kill: def $al killed $al killed $eax
+; AVX512-NEXT: retq
+ %c1 = fcmp ogt float %a, %b
+ %c2 = fcmp olt float %a, %c
+ %c3 = fcmp oeq float %a, %d
+ %c4 = fcmp une float %a, %e
+ %c5 = fcmp oge float %a, %f
+ %and1 = and i1 %c1, %c2
+ %and2 = and i1 %and1, %c3
+ %and3 = and i1 %and2, %c4
+ %and4 = and i1 %and3, %c5
+ ret i1 %and4
+}
+
+define i1 @mixed_or5_f64(double %a, double %b, double %c, double %d, double %e, double %f) {
+; SSE2-LABEL: mixed_or5_f64:
+; SSE2: # %bb.0:
+; SSE2-NEXT: ucomisd %xmm0, %xmm2
+; SSE2-NEXT: seta %al
+; SSE2-NEXT: cmpeqsd %xmm0, %xmm3
+; SSE2-NEXT: cmpltsd %xmm0, %xmm1
+; SSE2-NEXT: orpd %xmm3, %xmm1
+; SSE2-NEXT: movd %xmm1, %ecx
+; SSE2-NEXT: orb %al, %cl
+; SSE2-NEXT: cmplesd %xmm0, %xmm5
+; SSE2-NEXT: cmpneqsd %xmm0, %xmm4
+; SSE2-NEXT: orpd %xmm5, %xmm4
+; SSE2-NEXT: movd %xmm4, %eax
+; SSE2-NEXT: orb %cl, %al
+; SSE2-NEXT: # kill: def $al killed $al killed $eax
+; SSE2-NEXT: retq
+;
+; AVX1-LABEL: mixed_or5_f64:
+; AVX1: # %bb.0:
+; AVX1-NEXT: vucomisd %xmm0, %xmm2
+; AVX1-NEXT: seta %al
+; AVX1-NEXT: vcmpeqsd %xmm3, %xmm0, %xmm2
+; AVX1-NEXT: vcmpltsd %xmm0, %xmm1, %xmm1
+; AVX1-NEXT: vorpd %xmm2, %xmm1, %xmm1
+; AVX1-NEXT: vmovd %xmm1, %ecx
+; AVX1-NEXT: orb %al, %cl
+; AVX1-NEXT: vcmplesd %xmm0, %xmm5, %xmm1
+; AVX1-NEXT: vcmpneqsd %xmm4, %xmm0, %xmm0
+; AVX1-NEXT: vorpd %xmm1, %xmm0, %xmm0
+; AVX1-NEXT: vmovd %xmm0, %eax
+; AVX1-NEXT: orb %cl, %al
+; AVX1-NEXT: # kill: def $al killed $al killed $eax
+; AVX1-NEXT: retq
+;
+; AVX512-LABEL: mixed_or5_f64:
+; AVX512: # %bb.0:
+; AVX512-NEXT: vucomisd %xmm0, %xmm2
+; AVX512-NEXT: seta %al
+; AVX512-NEXT: vcmpeqsd %xmm3, %xmm0, %k0
+; AVX512-NEXT: vcmpltsd %xmm0, %xmm1, %k1
+; AVX512-NEXT: korw %k0, %k1, %k0
+; AVX512-NEXT: kmovw %k0, %ecx
+; AVX512-NEXT: orb %al, %cl
+; AVX512-NEXT: vcmplesd %xmm0, %xmm5, %k0
+; AVX512-NEXT: vcmpneqsd %xmm4, %xmm0, %k1
+; AVX512-NEXT: korw %k0, %k1, %k0
+; AVX512-NEXT: kmovw %k0, %eax
+; AVX512-NEXT: orb %cl, %al
+; AVX512-NEXT: # kill: def $al killed $al killed $eax
+; AVX512-NEXT: retq
+ %c1 = fcmp ogt double %a, %b
+ %c2 = fcmp olt double %a, %c
+ %c3 = fcmp oeq double %a, %d
+ %c4 = fcmp une double %a, %e
+ %c5 = fcmp oge double %a, %f
+ %or1 = or i1 %c1, %c2
+ %or2 = or i1 %or1, %c3
+ %or3 = or i1 %or2, %c4
+ %or4 = or i1 %or3, %c5
+ ret i1 %or4
+}
+
+; An integer compare in the middle of a chain of FP compares.
+define i1 @olt_icmp_ole_oge_and_f64(double %w, double %x, double %y, double %z, i32 %a, i32 %b) {
+; SSE2-LABEL: olt_icmp_ole_oge_and_f64:
+; SSE2: # %bb.0:
+; SSE2-NEXT: ucomisd %xmm0, %xmm1
+; SSE2-NEXT: seta %al
+; SSE2-NEXT: cmpl %esi, %edi
+; SSE2-NEXT: setg %cl
+; SSE2-NEXT: andb %al, %cl
+; SSE2-NEXT: cmplesd %xmm3, %xmm2
+; SSE2-NEXT: cmplesd %xmm0, %xmm3
+; SSE2-NEXT: andpd %xmm2, %xmm3
+; SSE2-NEXT: movd %xmm3, %eax
+; SSE2-NEXT: andb %cl, %al
+; SSE2-NEXT: # kill: def $al killed $al killed $eax
+; SSE2-NEXT: retq
+;
+; AVX1-LABEL: olt_icmp_ole_oge_and_f64:
+; AVX1: # %bb.0:
+; AVX1-NEXT: vucomisd %xmm0, %xmm1
+; AVX1-NEXT: seta %al
+; AVX1-NEXT: cmpl %esi, %edi
+; AVX1-NEXT: setg %cl
+; AVX1-NEXT: andb %al, %cl
+; AVX1-NEXT: vcmplesd %xmm0, %xmm3, %xmm0
+; AVX1-NEXT: vcmplesd %xmm3, %xmm2, %xmm1
+; AVX1-NEXT: vandpd %xmm0, %xmm1, %xmm0
+; AVX1-NEXT: vmovd %xmm0, %eax
+; AVX1-NEXT: andb %cl, %al
+; AVX1-NEXT: # kill: def $al killed $al killed $eax
+; AVX1-NEXT: retq
+;
+; AVX512-LABEL: olt_icmp_ole_oge_and_f64:
+; AVX512: # %bb.0:
+; AVX512-NEXT: vucomisd %xmm0, %xmm1
+; AVX512-NEXT: seta %al
+; AVX512-NEXT: cmpl %esi, %edi
+; AVX512-NEXT: setg %cl
+; AVX512-NEXT: andb %al, %cl
+; AVX512-NEXT: vcmplesd %xmm0, %xmm3, %k0
+; AVX512-NEXT: vcmplesd %xmm3, %xmm2, %k1
+; AVX512-NEXT: kandw %k0, %k1, %k0
+; AVX512-NEXT: kmovw %k0, %eax
+; AVX512-NEXT: andb %cl, %al
+; AVX512-NEXT: # kill: def $al killed $al killed $eax
+; AVX512-NEXT: retq
+ %f1 = fcmp olt double %w, %x
+ %i = icmp sgt i32 %a, %b
+ %f2 = fcmp ole double %y, %z
+ %f3 = fcmp oge double %w, %z
+ %and1 = and i1 %f1, %i
+ %and2 = and i1 %and1, %f2
+ %and3 = and i1 %and2, %f3
+ ret i1 %and3
+}
+
+define i1 @olt_ole_and_and_f64(double %a, double %b, double %c, double %d, double %w, double %x, double %y, double %z) {
+; SSE2-LABEL: olt_ole_and_and_f64:
+; SSE2: # %bb.0:
+; SSE2-NEXT: cmplesd %xmm3, %xmm2
+; SSE2-NEXT: cmpltsd %xmm1, %xmm0
+; SSE2-NEXT: andpd %xmm2, %xmm0
+; SSE2-NEXT: cmplesd %xmm7, %xmm6
+; SSE2-NEXT: cmpltsd %xmm5, %xmm4
+; SSE2-NEXT: andpd %xmm6, %xmm4
+; SSE2-NEXT: movd %xmm4, %ecx
+; SSE2-NEXT: movd %xmm0, %eax
+; SSE2-NEXT: andl %ecx, %eax
+; SSE2-NEXT: # kill: def $al killed $al killed $eax
+; SSE2-NEXT: retq
+;
+; AVX1-LABEL: olt_ole_and_and_f64:
+; AVX1: # %bb.0:
+; AVX1-NEXT: vcmplesd %xmm3, %xmm2, %xmm2
+; AVX1-NEXT: vcmpltsd %xmm1, %xmm0, %xmm0
+; AVX1-NEXT: vandpd %xmm2, %xmm0, %xmm0
+; AVX1-NEXT: vcmplesd %xmm7, %xmm6, %xmm1
+; AVX1-NEXT: vcmpltsd %xmm5, %xmm4, %xmm2
+; AVX1-NEXT: vandpd %xmm1, %xmm2, %xmm1
+; AVX1-NEXT: vmovd %xmm1, %ecx
+; AVX1-NEXT: vmovd %xmm0, %eax
+; AVX1-NEXT: andl %ecx, %eax
+; AVX1-NEXT: # kill: def $al killed $al killed $eax
+; AVX1-NEXT: retq
+;
+; AVX512-LABEL: olt_ole_and_and_f64:
+; AVX512: # %bb.0:
+; AVX512-NEXT: vcmplesd %xmm3, %xmm2, %k0
+; AVX512-NEXT: vcmpltsd %xmm1, %xmm0, %k1
+; AVX512-NEXT: kandw %k0, %k1, %k0
+; AVX512-NEXT: kmovw %k0, %ecx
+; AVX512-NEXT: vcmplesd %xmm7, %xmm6, %k0
+; AVX512-NEXT: vcmpltsd %xmm5, %xmm4, %k1
+; AVX512-NEXT: kandw %k0, %k1, %k0
+; AVX512-NEXT: kmovw %k0, %eax
+; AVX512-NEXT: andb %cl, %al
+; AVX512-NEXT: # kill: def $al killed $al killed $eax
+; AVX512-NEXT: retq
+ %f1 = fcmp olt double %a, %b
+ %f2 = fcmp ole double %c, %d
+ %f3 = fcmp olt double %w, %x
+ %f4 = fcmp ole double %y, %z
+ %and1 = and i1 %f1, %f2
+ %and2 = and i1 %f3, %f4
+ %and3 = and i1 %and1, %and2
+ ret i1 %and3
+}
+
+define i1 @mixed_xor5_f32(float %a, float %b, float %c, float %d, float %e, float %f) {
+; SSE2-LABEL: mixed_xor5_f32:
+; SSE2: # %bb.0:
+; SSE2-NEXT: ucomiss %xmm0, %xmm2
+; SSE2-NEXT: seta %al
+; SSE2-NEXT: cmpeqss %xmm0, %xmm3
+; SSE2-NEXT: cmpltss %xmm0, %xmm1
+; SSE2-NEXT: xorps %xmm3, %xmm1
+; SSE2-NEXT: movd %xmm1, %ecx
+; SSE2-NEXT: xorb %al, %cl
+; SSE2-NEXT: cmpless %xmm0, %xmm5
+; SSE2-NEXT: cmpneqss %xmm0, %xmm4
+; SSE2-NEXT: xorps %xmm5, %xmm4
+; SSE2-NEXT: movd %xmm4, %eax
+; SSE2-NEXT: xorb %cl, %al
+; SSE2-NEXT: # kill: def $al killed $al killed $eax
+; SSE2-NEXT: retq
+;
+; AVX1-LABEL: mixed_xor5_f32:
+; AVX1: # %bb.0:
+; AVX1-NEXT: vucomiss %xmm0, %xmm2
+; AVX1-NEXT: seta %al
+; AVX1-NEXT: vcmpeqss %xmm3, %xmm0, %xmm2
+; AVX1-NEXT: vcmpltss %xmm0, %xmm1, %xmm1
+; AVX1-NEXT: vxorps %xmm2, %xmm1, %xmm1
+; AVX1-NEXT: vmovd %xmm1, %ecx
+; AVX1-NEXT: xorb %al, %cl
+; AVX1-NEXT: vcmpless %xmm0, %xmm5, %xmm1
+; AVX1-NEXT: vcmpneqss %xmm4, %xmm0, %xmm0
+; AVX1-NEXT: vxorps %xmm1, %xmm0, %xmm0
+; AVX1-NEXT: vmovd %xmm0, %eax
+; AVX1-NEXT: xorb %cl, %al
+; AVX1-NEXT: # kill: def $al killed $al killed $eax
+; AVX1-NEXT: retq
+;
+; AVX512-LABEL: mixed_xor5_f32:
+; AVX512: # %bb.0:
+; AVX512-NEXT: vucomiss %xmm0, %xmm2
+; AVX512-NEXT: seta %al
+; AVX512-NEXT: vcmpeqss %xmm3, %xmm0, %k0
+; AVX512-NEXT: vcmpltss %xmm0, %xmm1, %k1
+; AVX512-NEXT: kxorw %k0, %k1, %k0
+; AVX512-NEXT: kmovw %k0, %ecx
+; AVX512-NEXT: xorb %al, %cl
+; AVX512-NEXT: vcmpless %xmm0, %xmm5, %k0
+; AVX512-NEXT: vcmpneqss %xmm4, %xmm0, %k1
+; AVX512-NEXT: kxorw %k0, %k1, %k0
+; AVX512-NEXT: kmovw %k0, %eax
+; AVX512-NEXT: xorb %cl, %al
+; AVX512-NEXT: # kill: def $al killed $al killed $eax
+; AVX512-NEXT: retq
+ %c1 = fcmp ogt float %a, %b
+ %c2 = fcmp olt float %a, %c
+ %c3 = fcmp oeq float %a, %d
+ %c4 = fcmp une float %a, %e
+ %c5 = fcmp oge float %a, %f
+ %xor1 = xor i1 %c1, %c2
+ %xor2 = xor i1 %xor1, %c3
+ %xor3 = xor i1 %xor2, %c4
+ %xor4 = xor i1 %xor3, %c5
+ ret i1 %xor4
+}
+
+define i1 @olt_and10_f64(double %a, double %b0, double %b1, double %b2, double %b3, double %b4, double %b5, double %b6, double %b7, double %b8, double %b9) {
+; SSE2-LABEL: olt_and10_f64:
+; SSE2: # %bb.0:
+; SSE2-NEXT: movapd %xmm0, %xmm8
+; SSE2-NEXT: cmpltsd %xmm2, %xmm8
+; SSE2-NEXT: movapd %xmm0, %xmm2
+; SSE2-NEXT: cmpltsd %xmm1, %xmm2
+; SSE2-NEXT: andpd %xmm8, %xmm2
+; SSE2-NEXT: movd %xmm2, %eax
+; SSE2-NEXT: movapd %xmm0, %xmm1
+; SSE2-NEXT: cmpltsd %xmm4, %xmm1
+; SSE2-NEXT: movapd %xmm0, %xmm2
+; SSE2-NEXT: cmpltsd %xmm3, %xmm2
+; SSE2-NEXT: andpd %xmm1, %xmm2
+; SSE2-NEXT: movd %xmm2, %ecx
+; SSE2-NEXT: andl %eax, %ecx
+; SSE2-NEXT: movapd %xmm0, %xmm1
+; SSE2-NEXT: cmpltsd %xmm6, %xmm1
+; SSE2-NEXT: movapd %xmm0, %xmm2
+; SSE2-NEXT: cmpltsd %xmm5, %xmm2
+; SSE2-NEXT: andpd %xmm1, %xmm2
+; SSE2-NEXT: movd %xmm2, %eax
+; SSE2-NEXT: andl %ecx, %eax
+; SSE2-NEXT: movapd %xmm0, %xmm1
+; SSE2-NEXT: cmpltsd %xmm7, %xmm1
+; SSE2-NEXT: movapd %xmm0, %xmm2
+; SSE2-NEXT: cmpltsd {{[0-9]+}}(%rsp), %xmm2
+; SSE2-NEXT: andpd %xmm1, %xmm2
+; SSE2-NEXT: movd %xmm2, %ecx
+; SSE2-NEXT: andl %eax, %ecx
+; SSE2-NEXT: movapd %xmm0, %xmm1
+; SSE2-NEXT: cmpltsd {{[0-9]+}}(%rsp), %xmm1
+; SSE2-NEXT: cmpltsd {{[0-9]+}}(%rsp), %xmm0
+; SSE2-NEXT: andpd %xmm1, %xmm0
+; SSE2-NEXT: movd %xmm0, %eax
+; SSE2-NEXT: andl %ecx, %eax
+; SSE2-NEXT: # kill: def $al killed $al killed $eax
+; SSE2-NEXT: retq
+;
+; AVX1-LABEL: olt_and10_f64:
+; AVX1: # %bb.0:
+; AVX1-NEXT: vcmpltsd %xmm2, %xmm0, %xmm2
+; AVX1-NEXT: vcmpltsd %xmm1, %xmm0, %xmm1
+; AVX1-NEXT: vandpd %xmm2, %xmm1, %xmm1
+; AVX1-NEXT: vmovd %xmm1, %eax
+; AVX1-NEXT: vcmpltsd %xmm4, %xmm0, %xmm1
+; AVX1-NEXT: vcmpltsd %xmm3, %xmm0, %xmm2
+; AVX1-NEXT: vandpd %xmm1, %xmm2, %xmm1
+; AVX1-NEXT: vmovd %xmm1, %ecx
+; AVX1-NEXT: andl %eax, %ecx
+; AVX1-NEXT: vcmpltsd %xmm6, %xmm0, %xmm1
+; AVX1-NEXT: vcmpltsd %xmm5, %xmm0, %xmm2
+; AVX1-NEXT: vandpd %xmm1, %xmm2, %xmm1
+; AVX1-NEXT: vmovd %xmm1, %eax
+; AVX1-NEXT: andl %ecx, %eax
+; AVX1-NEXT: vcmpltsd %xmm7, %xmm0, %xmm1
+; AVX1-NEXT: vcmpltsd {{[0-9]+}}(%rsp), %xmm0, %xmm2
+; AVX1-NEXT: vandpd %xmm2, %xmm1, %xmm1
+; AVX1-NEXT: vmovd %xmm1, %ecx
+; AVX1-NEXT: andl %eax, %ecx
+; AVX1-NEXT: vcmpltsd {{[0-9]+}}(%rsp), %xmm0, %xmm1
+; AVX1-NEXT: vcmpltsd {{[0-9]+}}(%rsp), %xmm0, %xmm0
+; AVX1-NEXT: vandpd %xmm1, %xmm0, %xmm0
+; AVX1-NEXT: vmovd %xmm0, %eax
+; AVX1-NEXT: andl %ecx, %eax
+; AVX1-NEXT: # kill: def $al killed $al killed $eax
+; AVX1-NEXT: retq
+;
+; AVX512-LABEL: olt_and10_f64:
+; AVX512: # %bb.0:
+; AVX512-NEXT: vcmpltsd %xmm2, %xmm0, %k0
+; AVX512-NEXT: vcmpltsd %xmm1, %xmm0, %k1
+; AVX512-NEXT: kandw %k0, %k1, %k0
+; AVX512-NEXT: kmovw %k0, %eax
+; AVX512-NEXT: vcmpltsd %xmm4, %xmm0, %k0
+; AVX512-NEXT: vcmpltsd %xmm3, %xmm0, %k1
+; AVX512-NEXT: kandw %k0, %k1, %k0
+; AVX512-NEXT: kmovw %k0, %ecx
+; AVX512-NEXT: andb %al, %cl
+; AVX512-NEXT: vcmpltsd %xmm6, %xmm0, %k0
+; AVX512-NEXT: vcmpltsd %xmm5, %xmm0, %k1
+; AVX512-NEXT: kandw %k0, %k1, %k0
+; AVX512-NEXT: kmovw %k0, %eax
+; AVX512-NEXT: andb %cl, %al
+; AVX512-NEXT: vcmpltsd %xmm7, %xmm0, %k0
+; AVX512-NEXT: vcmpltsd {{[0-9]+}}(%rsp), %xmm0, %k1
+; AVX512-NEXT: kandw %k1, %k0, %k0
+; AVX512-NEXT: kmovw %k0, %ecx
+; AVX512-NEXT: andb %al, %cl
+; AVX512-NEXT: vcmpltsd {{[0-9]+}}(%rsp), %xmm0, %k0
+; AVX512-NEXT: vcmpltsd {{[0-9]+}}(%rsp), %xmm0, %k1
+; AVX512-NEXT: kandw %k0, %k1, %k0
+; AVX512-NEXT: kmovw %k0, %eax
+; AVX512-NEXT: andb %cl, %al
+; AVX512-NEXT: # kill: def $al killed $al killed $eax
+; AVX512-NEXT: retq
+ %c0 = fcmp olt double %a, %b0
+ %c1 = fcmp olt double %a, %b1
+ %c2 = fcmp olt double %a, %b2
+ %c3 = fcmp olt double %a, %b3
+ %c4 = fcmp olt double %a, %b4
+ %c5 = fcmp olt double %a, %b5
+ %c6 = fcmp olt double %a, %b6
+ %c7 = fcmp olt double %a, %b7
+ %c8 = fcmp olt double %a, %b8
+ %c9 = fcmp olt double %a, %b9
+ %and1 = and i1 %c0, %c1
+ %and2 = and i1 %and1, %c2
+ %and3 = and i1 %and2, %c3
+ %and4 = and i1 %and3, %c4
+ %and5 = and i1 %and4, %c5
+ %and6 = and i1 %and5, %c6
+ %and7 = and i1 %and6, %c7
+ %and8 = and i1 %and7, %c8
+ %and9 = and i1 %and8, %c9
+ ret i1 %and9
+}
+
+; Merge two converted sequences near the depth limit.
+define i1 @olt_and5_and5_f64(double %a, double %b0, double %b1, double %b2, double %b3, double %b4, double %b5, double %b6, double %b7, double %b8, double %b9) {
+; SSE2-LABEL: olt_and5_and5_f64:
+; SSE2: # %bb.0:
+; SSE2-NEXT: ucomisd %xmm0, %xmm2
+; SSE2-NEXT: seta %al
+; SSE2-NEXT: ucomisd %xmm0, %xmm7
+; SSE2-NEXT: seta %cl
+; SSE2-NEXT: movapd %xmm0, %xmm2
+; SSE2-NEXT: cmpltsd %xmm3, %xmm2
+; SSE2-NEXT: movapd %xmm0, %xmm3
+; SSE2-NEXT: cmpltsd %xmm1, %xmm3
+; SSE2-NEXT: andpd %xmm2, %xmm3
+; SSE2-NEXT: movd %xmm3, %edx
+; SSE2-NEXT: andb %al, %dl
+; SSE2-NEXT: movapd %xmm0, %xmm1
+; SSE2-NEXT: cmpltsd %xmm5, %xmm1
+; SSE2-NEXT: movapd %xmm0, %xmm2
+; SSE2-NEXT: cmpltsd %xmm4, %xmm2
+; SSE2-NEXT: andpd %xmm1, %xmm2
+; SSE2-NEXT: movd %xmm2, %esi
+; SSE2-NEXT: andb %dl, %sil
+; SSE2-NEXT: movapd %xmm0, %xmm1
+; SSE2-NEXT: cmpltsd %xmm6, %xmm1
+; SSE2-NEXT: movapd %xmm0, %xmm2
+; SSE2-NEXT: cmpltsd {{[0-9]+}}(%rsp), %xmm2
+; SSE2-NEXT: andpd %xmm1, %xmm2
+; SSE2-NEXT: movd %xmm2, %edx
+; SSE2-NEXT: andb %cl, %dl
+; SSE2-NEXT: movapd %xmm0, %xmm1
+; SSE2-NEXT: cmpltsd {{[0-9]+}}(%rsp), %xmm1
+; SSE2-NEXT: cmpltsd {{[0-9]+}}(%rsp), %xmm0
+; SSE2-NEXT: andpd %xmm1, %xmm0
+; SSE2-NEXT: movd %xmm0, %eax
+; SSE2-NEXT: andb %dl, %al
+; SSE2-NEXT: andb %sil, %al
+; SSE2-NEXT: # kill: def $al killed $al killed $eax
+; SSE2-NEXT: retq
+;
+; AVX1-LABEL: olt_and5_and5_f64:
+; AVX1: # %bb.0:
+; AVX1-NEXT: vucomisd %xmm0, %xmm2
+; AVX1-NEXT: seta %al
+; AVX1-NEXT: vucomisd %xmm0, %xmm7
+; AVX1-NEXT: seta %cl
+; AVX1-NEXT: vcmpltsd %xmm3, %xmm0, %xmm2
+; AVX1-NEXT: vcmpltsd %xmm1, %xmm0, %xmm1
+; AVX1-NEXT: vandpd %xmm2, %xmm1, %xmm1
+; AVX1-NEXT: vmovd %xmm1, %edx
+; AVX1-NEXT: andb %al, %dl
+; AVX1-NEXT: vcmpltsd %xmm5, %xmm0, %xmm1
+; AVX1-NEXT: vcmpltsd %xmm4, %xmm0, %xmm2
+; AVX1-NEXT: vandpd %xmm1, %xmm2, %xmm1
+; AVX1-NEXT: vmovd %xmm1, %esi
+; AVX1-NEXT: andb %dl, %sil
+; AVX1-NEXT: vcmpltsd %xmm6, %xmm0, %xmm1
+; AVX1-NEXT: vcmpltsd {{[0-9]+}}(%rsp), %xmm0, %xmm2
+; AVX1-NEXT: vandpd %xmm2, %xmm1, %xmm1
+; AVX1-NEXT: vmovd %xmm1, %edx
+; AVX1-NEXT: andb %cl, %dl
+; AVX1-NEXT: vcmpltsd {{[0-9]+}}(%rsp), %xmm0, %xmm1
+; AVX1-NEXT: vcmpltsd {{[0-9]+}}(%rsp), %xmm0, %xmm0
+; AVX1-NEXT: vandpd %xmm1, %xmm0, %xmm0
+; AVX1-NEXT: vmovd %xmm0, %eax
+; AVX1-NEXT: andb %dl, %al
+; AVX1-NEXT: andb %sil, %al
+; AVX1-NEXT: # kill: def $al killed $al killed $eax
+; AVX1-NEXT: retq
+;
+; AVX512-LABEL: olt_and5_and5_f64:
+; AVX512: # %bb.0:
+; AVX512-NEXT: vucomisd %xmm0, %xmm2
+; AVX512-NEXT: seta %al
+; AVX512-NEXT: vucomisd %xmm0, %xmm7
+; AVX512-NEXT: seta %cl
+; AVX512-NEXT: vcmpltsd %xmm3, %xmm0, %k0
+; AVX512-NEXT: vcmpltsd %xmm1, %xmm0, %k1
+; AVX512-NEXT: kandw %k0, %k1, %k0
+; AVX512-NEXT: kmovw %k0, %edx
+; AVX512-NEXT: andb %al, %dl
+; AVX512-NEXT: vcmpltsd %xmm5, %xmm0, %k0
+; AVX512-NEXT: vcmpltsd %xmm4, %xmm0, %k1
+; AVX512-NEXT: kandw %k0, %k1, %k0
+; AVX512-NEXT: kmovw %k0, %esi
+; AVX512-NEXT: andb %dl, %sil
+; AVX512-NEXT: vcmpltsd %xmm6, %xmm0, %k0
+; AVX512-NEXT: vcmpltsd {{[0-9]+}}(%rsp), %xmm0, %k1
+; AVX512-NEXT: kandw %k1, %k0, %k0
+; AVX512-NEXT: kmovw %k0, %edx
+; AVX512-NEXT: andb %cl, %dl
+; AVX512-NEXT: vcmpltsd {{[0-9]+}}(%rsp), %xmm0, %k0
+; AVX512-NEXT: vcmpltsd {{[0-9]+}}(%rsp), %xmm0, %k1
+; AVX512-NEXT: kandw %k0, %k1, %k0
+; AVX512-NEXT: kmovw %k0, %eax
+; AVX512-NEXT: andb %dl, %al
+; AVX512-NEXT: andb %sil, %al
+; AVX512-NEXT: # kill: def $al killed $al killed $eax
+; AVX512-NEXT: retq
+ %c0 = fcmp olt double %a, %b0
+ %c1 = fcmp olt double %a, %b1
+ %c2 = fcmp olt double %a, %b2
+ %c3 = fcmp olt double %a, %b3
+ %c4 = fcmp olt double %a, %b4
+ %c5 = fcmp olt double %a, %b5
+ %c6 = fcmp olt double %a, %b6
+ %c7 = fcmp olt double %a, %b7
+ %c8 = fcmp olt double %a, %b8
+ %c9 = fcmp olt double %a, %b9
+ %l1 = and i1 %c0, %c1
+ %l2 = and i1 %l1, %c2
+ %l3 = and i1 %l2, %c3
+ %l4 = and i1 %l3, %c4
+ %r1 = and i1 %c5, %c6
+ %r2 = and i1 %r1, %c7
+ %r3 = and i1 %r2, %c8
+ %r4 = and i1 %r3, %c9
+ %and = and i1 %l4, %r4
+ ret i1 %and
+}
+
+; An integer compare in the middle of a long chain of FP compares.
+define i1 @olt_and8_icmp_f64(double %a, double %b0, double %b1, double %b2, double %b3, double %b4, double %b5, double %b6, double %b7, i32 %x, i32 %y) {
+; SSE2-LABEL: olt_and8_icmp_f64:
+; SSE2: # %bb.0:
+; SSE2-NEXT: cmpl %esi, %edi
+; SSE2-NEXT: setl %al
+; SSE2-NEXT: movapd %xmm0, %xmm8
+; SSE2-NEXT: cmpltsd %xmm2, %xmm8
+; SSE2-NEXT: movapd %xmm0, %xmm2
+; SSE2-NEXT: cmpltsd %xmm1, %xmm2
+; SSE2-NEXT: andpd %xmm8, %xmm2
+; SSE2-NEXT: movd %xmm2, %ecx
+; SSE2-NEXT: movapd %xmm0, %xmm1
+; SSE2-NEXT: cmpltsd %xmm4, %xmm1
+; SSE2-NEXT: movapd %xmm0, %xmm2
+; SSE2-NEXT: cmpltsd %xmm3, %xmm2
+; SSE2-NEXT: andpd %xmm1, %xmm2
+; SSE2-NEXT: movd %xmm2, %edx
+; SSE2-NEXT: andl %ecx, %edx
+; SSE2-NEXT: movapd %xmm0, %xmm1
+; SSE2-NEXT: cmpltsd %xmm6, %xmm1
+; SSE2-NEXT: movapd %xmm0, %xmm2
+; SSE2-NEXT: cmpltsd %xmm5, %xmm2
+; SSE2-NEXT: andpd %xmm1, %xmm2
+; SSE2-NEXT: movd %xmm2, %ecx
+; SSE2-NEXT: andb %al, %cl
+; SSE2-NEXT: andb %dl, %cl
+; SSE2-NEXT: movapd %xmm0, %xmm1
+; SSE2-NEXT: cmpltsd %xmm7, %xmm1
+; SSE2-NEXT: cmpltsd {{[0-9]+}}(%rsp), %xmm0
+; SSE2-NEXT: andpd %xmm1, %xmm0
+; SSE2-NEXT: movd %xmm0, %eax
+; SSE2-NEXT: andb %cl, %al
+; SSE2-NEXT: # kill: def $al killed $al killed $eax
+; SSE2-NEXT: retq
+;
+; AVX1-LABEL: olt_and8_icmp_f64:
+; AVX1: # %bb.0:
+; AVX1-NEXT: cmpl %esi, %edi
+; AVX1-NEXT: setl %al
+; AVX1-NEXT: vcmpltsd %xmm2, %xmm0, %xmm2
+; AVX1-NEXT: vcmpltsd %xmm1, %xmm0, %xmm1
+; AVX1-NEXT: vandpd %xmm2, %xmm1, %xmm1
+; AVX1-NEXT: vmovd %xmm1, %ecx
+; AVX1-NEXT: vcmpltsd %xmm4, %xmm0, %xmm1
+; AVX1-NEXT: vcmpltsd %xmm3, %xmm0, %xmm2
+; AVX1-NEXT: vandpd %xmm1, %xmm2, %xmm1
+; AVX1-NEXT: vmovd %xmm1, %edx
+; AVX1-NEXT: andl %ecx, %edx
+; AVX1-NEXT: vcmpltsd %xmm6, %xmm0, %xmm1
+; AVX1-NEXT: vcmpltsd %xmm5, %xmm0, %xmm2
+; AVX1-NEXT: vandpd %xmm1, %xmm2, %xmm1
+; AVX1-NEXT: vmovd %xmm1, %ecx
+; AVX1-NEXT: andb %al, %cl
+; AVX1-NEXT: andb %dl, %cl
+; AVX1-NEXT: vcmpltsd %xmm7, %xmm0, %xmm1
+; AVX1-NEXT: vcmpltsd {{[0-9]+}}(%rsp), %xmm0, %xmm0
+; AVX1-NEXT: vandpd %xmm0, %xmm1, %xmm0
+; AVX1-NEXT: vmovd %xmm0, %eax
+; AVX1-NEXT: andb %cl, %al
+; AVX1-NEXT: # kill: def $al killed $al killed $eax
+; AVX1-NEXT: retq
+;
+; AVX512-LABEL: olt_and8_icmp_f64:
+; AVX512: # %bb.0:
+; AVX512-NEXT: cmpl %esi, %edi
+; AVX512-NEXT: setl %al
+; AVX512-NEXT: vcmpltsd %xmm2, %xmm0, %k0
+; AVX512-NEXT: vcmpltsd %xmm1, %xmm0, %k1
+; AVX512-NEXT: kandw %k0, %k1, %k0
+; AVX512-NEXT: kmovw %k0, %ecx
+; AVX512-NEXT: vcmpltsd %xmm4, %xmm0, %k0
+; AVX512-NEXT: vcmpltsd %xmm3, %xmm0, %k1
+; AVX512-NEXT: kandw %k0, %k1, %k0
+; AVX512-NEXT: kmovw %k0, %edx
+; AVX512-NEXT: andb %cl, %dl
+; AVX512-NEXT: vcmpltsd %xmm6, %xmm0, %k0
+; AVX512-NEXT: vcmpltsd %xmm5, %xmm0, %k1
+; AVX512-NEXT: kandw %k0, %k1, %k0
+; AVX512-NEXT: kmovw %k0, %ecx
+; AVX512-NEXT: andb %al, %cl
+; AVX512-NEXT: andb %dl, %cl
+; AVX512-NEXT: vcmpltsd %xmm7, %xmm0, %k0
+; AVX512-NEXT: vcmpltsd {{[0-9]+}}(%rsp), %xmm0, %k1
+; AVX512-NEXT: kandw %k1, %k0, %k0
+; AVX512-NEXT: kmovw %k0, %eax
+; AVX512-NEXT: andb %cl, %al
+; AVX512-NEXT: # kill: def $al killed $al killed $eax
+; AVX512-NEXT: retq
+ %c0 = fcmp olt double %a, %b0
+ %c1 = fcmp olt double %a, %b1
+ %c2 = fcmp olt double %a, %b2
+ %c3 = fcmp olt double %a, %b3
+ %c4 = fcmp olt double %a, %b4
+ %c5 = fcmp olt double %a, %b5
+ %c6 = fcmp olt double %a, %b6
+ %c7 = fcmp olt double %a, %b7
+ %i = icmp slt i32 %x, %y
+ %and1 = and i1 %c0, %c1
+ %and2 = and i1 %and1, %c2
+ %and3 = and i1 %and2, %c3
+ %and4 = and i1 %and3, %i
+ %and5 = and i1 %and4, %c4
+ %and6 = and i1 %and5, %c5
+ %and7 = and i1 %and6, %c6
+ %and8 = and i1 %and7, %c7
+ ret i1 %and8
+}
+
+; Negative test: FP compares of different types are not combined.
+define i1 @olt_ole_and_f32_f64(float %a, float %b, float %c, float %d, double %w, double %x, double %y, double %z) {
+; SSE2-LABEL: olt_ole_and_f32_f64:
+; SSE2: # %bb.0:
+; SSE2-NEXT: cmpless %xmm3, %xmm2
+; SSE2-NEXT: cmpltss %xmm1, %xmm0
+; SSE2-NEXT: andps %xmm2, %xmm0
+; SSE2-NEXT: movd %xmm0, %ecx
+; SSE2-NEXT: cmplesd %xmm7, %xmm6
+; SSE2-NEXT: cmpltsd %xmm5, %xmm4
+; SSE2-NEXT: andpd %xmm6, %xmm4
+; SSE2-NEXT: movd %xmm4, %eax
+; SSE2-NEXT: andl %ecx, %eax
+; SSE2-NEXT: # kill: def $al killed $al killed $eax
+; SSE2-NEXT: retq
+;
+; AVX1-LABEL: olt_ole_and_f32_f64:
+; AVX1: # %bb.0:
+; AVX1-NEXT: vcmpless %xmm3, %xmm2, %xmm2
+; AVX1-NEXT: vcmpltss %xmm1, %xmm0, %xmm0
+; AVX1-NEXT: vandps %xmm2, %xmm0, %xmm0
+; AVX1-NEXT: vmovd %xmm0, %ecx
+; AVX1-NEXT: vcmplesd %xmm7, %xmm6, %xmm0
+; AVX1-NEXT: vcmpltsd %xmm5, %xmm4, %xmm1
+; AVX1-NEXT: vandpd %xmm0, %xmm1, %xmm0
+; AVX1-NEXT: vmovd %xmm0, %eax
+; AVX1-NEXT: andl %ecx, %eax
+; AVX1-NEXT: # kill: def $al killed $al killed $eax
+; AVX1-NEXT: retq
+;
+; AVX512-LABEL: olt_ole_and_f32_f64:
+; AVX512: # %bb.0:
+; AVX512-NEXT: vcmpless %xmm3, %xmm2, %k0
+; AVX512-NEXT: vcmpltss %xmm1, %xmm0, %k1
+; AVX512-NEXT: kandw %k0, %k1, %k0
+; AVX512-NEXT: kmovw %k0, %ecx
+; AVX512-NEXT: vcmplesd %xmm7, %xmm6, %k0
+; AVX512-NEXT: vcmpltsd %xmm5, %xmm4, %k1
+; AVX512-NEXT: kandw %k0, %k1, %k0
+; AVX512-NEXT: kmovw %k0, %eax
+; AVX512-NEXT: andb %cl, %al
+; AVX512-NEXT: # kill: def $al killed $al killed $eax
+; AVX512-NEXT: retq
+ %f1 = fcmp olt float %a, %b
+ %f2 = fcmp ole float %c, %d
+ %f3 = fcmp olt double %w, %x
+ %f4 = fcmp ole double %y, %z
+ %and1 = and i1 %f1, %f2
+ %and2 = and i1 %f3, %f4
+ %and3 = and i1 %and1, %and2
+ ret i1 %and3
+}
+
+; Negative test: the converted FP compares have another use.
+define i1 @olt_ole_oge_and_f64_use(double %w, double %x, double %y, double %z, ptr %p) {
+; SSE2-LABEL: olt_ole_oge_and_f64_use:
+; SSE2: # %bb.0:
+; SSE2-NEXT: ucomisd %xmm3, %xmm0
+; SSE2-NEXT: setae %al
+; SSE2-NEXT: cmplesd %xmm3, %xmm2
+; SSE2-NEXT: cmpltsd %xmm1, %xmm0
+; SSE2-NEXT: andpd %xmm2, %xmm0
+; SSE2-NEXT: movd %xmm0, %ecx
+; SSE2-NEXT: andb %cl, %al
+; SSE2-NEXT: # kill: def $cl killed $cl killed $ecx
+; SSE2-NEXT: andb $1, %cl
+; SSE2-NEXT: movb %cl, (%rdi)
+; SSE2-NEXT: retq
+;
+; AVX1-LABEL: olt_ole_oge_and_f64_use:
+; AVX1: # %bb.0:
+; AVX1-NEXT: vucomisd %xmm3, %xmm0
+; AVX1-NEXT: setae %al
+; AVX1-NEXT: vcmplesd %xmm3, %xmm2, %xmm2
+; AVX1-NEXT: vcmpltsd %xmm1, %xmm0, %xmm0
+; AVX1-NEXT: vandpd %xmm2, %xmm0, %xmm0
+; AVX1-NEXT: vmovd %xmm0, %ecx
+; AVX1-NEXT: andb %cl, %al
+; AVX1-NEXT: # kill: def $cl killed $cl killed $ecx
+; AVX1-NEXT: andb $1, %cl
+; AVX1-NEXT: movb %cl, (%rdi)
+; AVX1-NEXT: retq
+;
+; AVX512-LABEL: olt_ole_oge_and_f64_use:
+; AVX512: # %bb.0:
+; AVX512-NEXT: vucomisd %xmm3, %xmm0
+; AVX512-NEXT: setae %al
+; AVX512-NEXT: vcmplesd %xmm3, %xmm2, %k0
+; AVX512-NEXT: vcmpltsd %xmm1, %xmm0, %k1
+; AVX512-NEXT: kandw %k0, %k1, %k0
+; AVX512-NEXT: kmovw %k0, %ecx
+; AVX512-NEXT: andb %cl, %al
+; AVX512-NEXT: # kill: def $cl killed $cl killed $ecx
+; AVX512-NEXT: andb $1, %cl
+; AVX512-NEXT: movb %cl, (%rdi)
+; AVX512-NEXT: retq
+ %f1 = fcmp olt double %w, %x
+ %f2 = fcmp ole double %y, %z
+ %f3 = fcmp oge double %w, %z
+ %and1 = and i1 %f1, %f2
+ store i1 %and1, ptr %p
+ %and2 = and i1 %and1, %f3
+ ret i1 %and2
+}
+
+; Negative tests: vector logic that does not come from scalar FP compares.
+define i1 @v2i1_xor_olt_and_f64(<2 x i1> %a, <2 x i1> %b, double %x, double %y) {
+; SSE2-LABEL: v2i1_xor_olt_and_f64:
+; SSE2: # %bb.0:
+; SSE2-NEXT: pxor %xmm1, %xmm0
+; SSE2-NEXT: movd %xmm0, %ecx
+; SSE2-NEXT: ucomisd %xmm2, %xmm3
+; SSE2-NEXT: seta %al
+; SSE2-NEXT: andb %cl, %al
+; SSE2-NEXT: retq
+;
+; AVX-LABEL: v2i1_xor_olt_and_f64:
+; AVX: # %bb.0:
+; AVX-NEXT: vpxor %xmm1, %xmm0, %xmm0
+; AVX-NEXT: vmovd %xmm0, %ecx
+; AVX-NEXT: vucomisd %xmm2, %xmm3
+; AVX-NEXT: seta %al
+; AVX-NEXT: andb %cl, %al
+; AVX-NEXT: retq
+ %v = xor <2 x i1> %a, %b
+ %e = extractelement <2 x i1> %v, i64 0
+ %c = fcmp olt double %x, %y
+ %r = and i1 %e, %c
+ ret i1 %r
+}
+
+define i1 @v4i1_xor_or_and(<4 x i1> %a, <4 x i1> %b, <4 x i1> %c, <4 x i1> %d) {
+; SSE2-LABEL: v4i1_xor_or_and:
+; SSE2: # %bb.0:
+; SSE2-NEXT: pxor %xmm1, %xmm0
+; SSE2-NEXT: movd %xmm0, %ecx
+; SSE2-NEXT: por %xmm3, %xmm2
+; SSE2-NEXT: movd %xmm2, %eax
+; SSE2-NEXT: andl %ecx, %eax
+; SSE2-NEXT: # kill: def $al killed $al killed $eax
+; SSE2-NEXT: retq
+;
+; AVX-LABEL: v4i1_xor_or_and:
+; AVX: # %bb.0:
+; AVX-NEXT: vpxor %xmm1, %xmm0, %xmm0
+; AVX-NEXT: vmovd %xmm0, %ecx
+; AVX-NEXT: vpor %xmm3, %xmm2, %xmm0
+; AVX-NEXT: vmovd %xmm0, %eax
+; AVX-NEXT: andl %ecx, %eax
+; AVX-NEXT: # kill: def $al killed $al killed $eax
+; AVX-NEXT: retq
+ %v0 = xor <4 x i1> %a, %b
+ %v1 = or <4 x i1> %c, %d
+ %e0 = extractelement <4 x i1> %v0, i64 0
+ %e1 = extractelement <4 x i1> %v1, i64 0
+ %r = and i1 %e0, %e1
+ ret i1 %r
+}
+
+define i1 @v4f32_olt_ole_and_f32(<4 x float> %a, <4 x float> %b, <4 x float> %c, float %x, float %y, float %z, float %w) {
+; SSE2-LABEL: v4f32_olt_ole_and_f32:
+; SSE2: # %bb.0:
+; SSE2-NEXT: movaps %xmm0, %xmm7
+; SSE2-NEXT: cmpltss %xmm1, %xmm7
+; SSE2-NEXT: cmpltss %xmm2, %xmm0
+; SSE2-NEXT: andps %xmm7, %xmm0
+; SSE2-NEXT: movd %xmm0, %ecx
+; SSE2-NEXT: cmpless %xmm6, %xmm5
+; SSE2-NEXT: cmpltss %xmm4, %xmm3
+; SSE2-NEXT: andps %xmm5, %xmm3
+; SSE2-NEXT: movd %xmm3, %eax
+; SSE2-NEXT: andl %ecx, %eax
+; SSE2-NEXT: # kill: def $al killed $al killed $eax
+; SSE2-NEXT: retq
+;
+; AVX1-LABEL: v4f32_olt_ole_and_f32:
+; AVX1: # %bb.0:
+; AVX1-NEXT: vcmpltss %xmm1, %xmm0, %xmm1
+; AVX1-NEXT: vcmpltss %xmm2, %xmm0, %xmm0
+; AVX1-NEXT: vandps %xmm0, %xmm1, %xmm0
+; AVX1-NEXT: vmovd %xmm0, %ecx
+; AVX1-NEXT: vcmpless %xmm6, %xmm5, %xmm0
+; AVX1-NEXT: vcmpltss %xmm4, %xmm3, %xmm1
+; AVX1-NEXT: vandps %xmm0, %xmm1, %xmm0
+; AVX1-NEXT: vmovd %xmm0, %eax
+; AVX1-NEXT: andl %ecx, %eax
+; AVX1-NEXT: # kill: def $al killed $al killed $eax
+; AVX1-NEXT: retq
+;
+; AVX512-LABEL: v4f32_olt_ole_and_f32:
+; AVX512: # %bb.0:
+; AVX512-NEXT: vcmpltss %xmm1, %xmm0, %k0
+; AVX512-NEXT: vcmpltss %xmm2, %xmm0, %k1
+; AVX512-NEXT: kandw %k1, %k0, %k0
+; AVX512-NEXT: kmovw %k0, %ecx
+; AVX512-NEXT: vcmpless %xmm6, %xmm5, %k0
+; AVX512-NEXT: vcmpltss %xmm4, %xmm3, %k1
+; AVX512-NEXT: kandw %k0, %k1, %k0
+; AVX512-NEXT: kmovw %k0, %eax
+; AVX512-NEXT: andb %cl, %al
+; AVX512-NEXT: # kill: def $al killed $al killed $eax
+; AVX512-NEXT: retq
+ %vc1 = fcmp olt <4 x float> %a, %b
+ %vc2 = fcmp olt <4 x float> %a, %c
+ %v = and <4 x i1> %vc1, %vc2
+ %e = extractelement <4 x i1> %v, i64 0
+ %f1 = fcmp olt float %x, %y
+ %f2 = fcmp ole float %z, %w
+ %and1 = and i1 %f1, %f2
+ %r = and i1 %e, %and1
+ ret i1 %r
+}
>From 412ebc21684140056f10c2084f300b0bd7f31fb8 Mon Sep 17 00:00:00 2001
From: Tim Besard <tim.besard at gmail.com>
Date: Thu, 24 Sep 2026 21:23:46 +0200
Subject: [PATCH 5/6] [X86] Add FP compares to already converted FP logic
convertIntLogicToFPLogic only pairs two scalar FP compares, so longer
chains end up as several vector pairs, each moved to a GPR and combined
with integer logic, plus leftover COMIS/SETcc compares.
Add FP compares, or another converted sequence of the same type, to the
vector logic of an already converted sequence, and let the nested logic
look-through pair a converted sequence as well. Only extend vector logic
over compares of scalar FP values, and limit its depth so that the final
extract still scalarizes all compares; longer chains are split into a few
sequences. Eligible single-use, same-type chains now stay in the SSE/mask
domain with a single move at the end.
Without AVX512VL, the v8f16 compares are not legal, so keep f16 compares
scalar there; the pair conversion was already a loss in that case.
Fixes #219468.
---
llvm/lib/Target/X86/X86ISelLowering.cpp | 91 +++-
llvm/test/CodeGen/X86/fcmp-logic-fp16.ll | 59 +--
llvm/test/CodeGen/X86/fcmp-logic.ll | 597 +++++++++++------------
3 files changed, 377 insertions(+), 370 deletions(-)
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index fe5af112e9eba..73ed56c14a1ef 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -52658,11 +52658,28 @@ static unsigned convertIntLogicToFPLogicOpcode(unsigned Opcode) {
return FPOpcode;
}
+/// Return true if \p V is a tree of single-use vector logic ops over vector
+/// compares of scalar FP values, as created by convertIntLogicToFPLogic. Limit
+/// the depth so that, after one more logic op is added,
+/// SimplifyDemandedVectorElts on the final extract still reaches every compare:
+/// otherwise the X86ISD::CMPM mask compares are not scalarized and are widened
+/// to 512 bits without AVX512VL.
+static bool isConvertedFPLogic(SDValue V, unsigned Depth = 0) {
+ if (V.getOpcode() == ISD::SETCC)
+ return V.getOperand(0).getOpcode() == ISD::SCALAR_TO_VECTOR &&
+ V.getOperand(0).getValueType().isFloatingPoint();
+ if (Depth >= SelectionDAG::MaxRecursionDepth - 2 ||
+ !ISD::isBitwiseLogicOp(V.getOpcode()) || !V.hasOneUse())
+ return false;
+ return isConvertedFPLogic(V.getOperand(0), Depth + 1) &&
+ isConvertedFPLogic(V.getOperand(1), Depth + 1);
+}
+
/// If both input operands of a logic op are being cast from floating-point
/// types or FP compares, try to convert this into a floating-point logic node
/// to avoid unnecessary moves from SSE to integer registers. For i1 logic, also
-/// look through one level of a nested logic op of the same kind to pair up two
-/// FP compares.
+/// add FP compares to ones that were already converted, and look through one
+/// level of a nested logic op of the same kind to pair up two FP compares.
static SDValue convertIntLogicToFPLogic(unsigned Opc, const SDLoc &DL, EVT VT,
SDValue N0, SDValue N1,
SelectionDAG &DAG,
@@ -52671,23 +52688,73 @@ static SDValue convertIntLogicToFPLogic(unsigned Opc, const SDLoc &DL, EVT VT,
assert((Opc == ISD::OR || Opc == ISD::AND || Opc == ISD::XOR) &&
"Unexpected bit opcode");
+ using namespace SDPatternMatch;
+ auto IsLegalFPType = [&](EVT FPVT) {
+ return (Subtarget.hasSSE1() && FPVT == MVT::f32) ||
+ (Subtarget.hasSSE2() && FPVT == MVT::f64) ||
+ (Subtarget.hasFP16() && FPVT == MVT::f16);
+ };
+ // Without AVX512VL, the v8f16 compares are not legal.
+ auto IsLegalFPCmpType = [&](EVT FPVT) {
+ return IsLegalFPType(FPVT) && (FPVT != MVT::f16 || Subtarget.hasVLX());
+ };
+
// Look through a single-use inner logic op to pair up two FP compares that
// it separates, e.g. by an integer compare. The recursive call only sees
- // SETCC operands, so this is limited to one level:
+ // SETCC or converted operands, so this is limited to one level:
// logic (logic (setcc X), Y), (setcc Z) -->
// logic (logic (setcc X), (setcc Z)), Y
- using namespace SDPatternMatch;
- auto FPSetCC = [](SDValue &Cmp) {
- return m_Value(Cmp, m_SetCC(m_FloatingPointVT(), m_Value(), m_Value()));
+ auto FPCmp = [](SDValue &Cmp) {
+ return m_Value(
+ Cmp,
+ m_AnyOf(m_SetCC(m_FloatingPointVT(), m_Value(), m_Value()),
+ m_ExtractElt(m_BitwiseLogic(m_Value(), m_Value()), m_Zero())));
};
SDValue X, Y, Z;
- auto Inner = m_OneUse(m_c_BinOp(Opc, FPSetCC(X), m_Value(Y)));
- if (VT == MVT::i1 && ((sd_match(N0, Inner) && sd_match(N1, FPSetCC(Z))) ||
- (sd_match(N1, Inner) && sd_match(N0, FPSetCC(Z)))))
+ auto Inner = m_OneUse(m_c_BinOp(Opc, FPCmp(X), m_Value(Y)));
+ if (VT == MVT::i1 && ((sd_match(N0, Inner) && sd_match(N1, FPCmp(Z))) ||
+ (sd_match(N1, Inner) && sd_match(N0, FPCmp(Z)))))
if (SDValue FPLogic =
convertIntLogicToFPLogic(Opc, DL, VT, X, Z, DAG, DCI, Subtarget))
return DAG.getNode(Opc, DL, VT, FPLogic, Y);
+ // Add an FP compare, or another converted sequence, to FP compares that
+ // were already converted to vector logic (see below):
+ // logic (extelt V, 0), (setcc LHS, RHS) -->
+ // extelt (logic V, (setcc (s2v LHS), (s2v RHS))), 0
+ // logic (extelt V, 0), (extelt W, 0) --> extelt (logic V, W), 0
+ auto IsConverted = [](SDValue Op, SDValue &Vec) {
+ return sd_match(Op, m_OneUse(m_ExtractElt(m_Value(Vec), m_Zero()))) &&
+ isConvertedFPLogic(Vec);
+ };
+ SDValue V, W, LHS, RHS;
+ ISD::CondCode CC;
+ if (VT == MVT::i1 && IsConverted(N1, V))
+ std::swap(N0, N1);
+ if (VT == MVT::i1 && IsConverted(N0, V)) {
+ EVT BoolVecVT = V.getValueType();
+ SDValue Vec1;
+ if (IsConverted(N1, W)) {
+ Vec1 = W;
+ } else if (sd_match(N1, m_OneUse(m_SetCC(m_Value(LHS), m_Value(RHS),
+ m_CondCode(CC)))) &&
+ IsLegalFPCmpType(LHS.getValueType()) &&
+ (Subtarget.hasAVX() || cheapX86FSETCC_SSE(CC))) {
+ EVT VecVT = EVT::getVectorVT(*DAG.getContext(), LHS.getValueType(),
+ BoolVecVT.getVectorNumElements());
+ if (VecVT.getSizeInBits() == 128) {
+ SDValue VecL = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, VecVT, LHS);
+ SDValue VecR = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, VecVT, RHS);
+ Vec1 = DAG.getSetCC(DL, BoolVecVT, VecL, VecR, CC);
+ }
+ }
+ if (Vec1 && Vec1.getValueType() == BoolVecVT) {
+ SDValue Logic = DAG.getNode(Opc, DL, BoolVecVT, V, Vec1);
+ return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, VT, Logic,
+ DAG.getVectorIdxConstant(0, DL));
+ }
+ }
+
if (!((N0.getOpcode() == ISD::BITCAST && N1.getOpcode() == ISD::BITCAST) ||
(N0.getOpcode() == ISD::SETCC && N1.getOpcode() == ISD::SETCC)))
return SDValue();
@@ -52698,9 +52765,7 @@ static SDValue convertIntLogicToFPLogic(unsigned Opc, const SDLoc &DL, EVT VT,
EVT N10Type = N10.getValueType();
// Ensure that both types are the same and are legal scalar fp types.
- if (N00Type != N10Type || !((Subtarget.hasSSE1() && N00Type == MVT::f32) ||
- (Subtarget.hasSSE2() && N00Type == MVT::f64) ||
- (Subtarget.hasFP16() && N00Type == MVT::f16)))
+ if (N00Type != N10Type || !IsLegalFPType(N00Type))
return SDValue();
if (N0.getOpcode() == ISD::BITCAST && !DCI.isBeforeLegalizeOps()) {
@@ -52710,7 +52775,7 @@ static SDValue convertIntLogicToFPLogic(unsigned Opc, const SDLoc &DL, EVT VT,
}
if (VT != MVT::i1 || N0.getOpcode() != ISD::SETCC || !N0.hasOneUse() ||
- !N1.hasOneUse())
+ !N1.hasOneUse() || !IsLegalFPCmpType(N00Type))
return SDValue();
ISD::CondCode CC0 = cast<CondCodeSDNode>(N0.getOperand(2))->get();
diff --git a/llvm/test/CodeGen/X86/fcmp-logic-fp16.ll b/llvm/test/CodeGen/X86/fcmp-logic-fp16.ll
index 35ea845d27497..caed749ec8894 100644
--- a/llvm/test/CodeGen/X86/fcmp-logic-fp16.ll
+++ b/llvm/test/CodeGen/X86/fcmp-logic-fp16.ll
@@ -5,15 +5,11 @@
define i1 @olt_ole_and_f16(half %w, half %x, half %y, half %z) {
; NOVL-LABEL: olt_ole_and_f16:
; NOVL: # %bb.0:
+; NOVL-NEXT: vucomish %xmm0, %xmm1
+; NOVL-NEXT: seta %cl
; NOVL-NEXT: vucomish %xmm2, %xmm3
; NOVL-NEXT: setae %al
-; NOVL-NEXT: kmovd %eax, %k0
-; NOVL-NEXT: vucomish %xmm0, %xmm1
-; NOVL-NEXT: seta %al
-; NOVL-NEXT: kmovd %eax, %k1
-; NOVL-NEXT: kandw %k0, %k1, %k0
-; NOVL-NEXT: kmovd %k0, %eax
-; NOVL-NEXT: # kill: def $al killed $al killed $eax
+; NOVL-NEXT: andb %cl, %al
; NOVL-NEXT: retq
;
; VL-LABEL: olt_ole_and_f16:
@@ -33,49 +29,38 @@ define i1 @olt_ole_and_f16(half %w, half %x, half %y, half %z) {
define i1 @mixed_and5_f16(half %a, half %b, half %c, half %d, half %e, half %f) {
; NOVL-LABEL: mixed_and5_f16:
; NOVL: # %bb.0:
-; NOVL-NEXT: vucomish %xmm0, %xmm2
-; NOVL-NEXT: seta %al
-; NOVL-NEXT: xorl %ecx, %ecx
-; NOVL-NEXT: vucomish %xmm3, %xmm0
-; NOVL-NEXT: movl $255, %edx
-; NOVL-NEXT: movl $255, %esi
-; NOVL-NEXT: cmovnel %ecx, %esi
-; NOVL-NEXT: cmovpl %ecx, %esi
-; NOVL-NEXT: kmovd %esi, %k0
; NOVL-NEXT: vucomish %xmm1, %xmm0
; NOVL-NEXT: seta %cl
-; NOVL-NEXT: kmovd %ecx, %k1
-; NOVL-NEXT: kandw %k0, %k1, %k0
-; NOVL-NEXT: kmovd %k0, %ecx
-; NOVL-NEXT: andb %al, %cl
-; NOVL-NEXT: xorl %eax, %eax
+; NOVL-NEXT: vucomish %xmm0, %xmm2
+; NOVL-NEXT: seta %dl
+; NOVL-NEXT: vucomish %xmm3, %xmm0
+; NOVL-NEXT: setnp %al
+; NOVL-NEXT: sete %sil
+; NOVL-NEXT: andb %al, %sil
; NOVL-NEXT: vucomish %xmm4, %xmm0
-; NOVL-NEXT: setne %al
-; NOVL-NEXT: cmovpl %edx, %eax
-; NOVL-NEXT: kmovd %eax, %k0
+; NOVL-NEXT: setp %al
+; NOVL-NEXT: setne %dil
+; NOVL-NEXT: orb %al, %dil
; NOVL-NEXT: vucomish %xmm5, %xmm0
; NOVL-NEXT: setae %al
-; NOVL-NEXT: kmovd %eax, %k1
-; NOVL-NEXT: kandw %k1, %k0, %k0
-; NOVL-NEXT: kmovd %k0, %eax
-; NOVL-NEXT: andb %cl, %al
-; NOVL-NEXT: # kill: def $al killed $al killed $eax
+; NOVL-NEXT: andb %cl, %dl
+; NOVL-NEXT: andb %sil, %dl
+; NOVL-NEXT: andb %dil, %al
+; NOVL-NEXT: andb %dl, %al
; NOVL-NEXT: retq
;
; VL-LABEL: mixed_and5_f16:
; VL: # %bb.0:
-; VL-NEXT: vucomish %xmm0, %xmm2
-; VL-NEXT: seta %al
-; VL-NEXT: vcmpeqsh %xmm3, %xmm0, %k0
-; VL-NEXT: vcmpltsh %xmm0, %xmm1, %k1
-; VL-NEXT: kandw %k0, %k1, %k0
-; VL-NEXT: kmovd %k0, %ecx
-; VL-NEXT: andb %al, %cl
; VL-NEXT: vcmplesh %xmm0, %xmm5, %k0
; VL-NEXT: vcmpneqsh %xmm4, %xmm0, %k1
; VL-NEXT: kandw %k0, %k1, %k0
+; VL-NEXT: vcmpeqsh %xmm3, %xmm0, %k1
+; VL-NEXT: kandw %k1, %k0, %k0
+; VL-NEXT: vcmpltsh %xmm0, %xmm1, %k1
+; VL-NEXT: kandw %k1, %k0, %k0
+; VL-NEXT: vcmpltsh %xmm2, %xmm0, %k1
+; VL-NEXT: kandw %k1, %k0, %k0
; VL-NEXT: kmovd %k0, %eax
-; VL-NEXT: andb %cl, %al
; VL-NEXT: # kill: def $al killed $al killed $eax
; VL-NEXT: retq
%c1 = fcmp ogt half %a, %b
diff --git a/llvm/test/CodeGen/X86/fcmp-logic.ll b/llvm/test/CodeGen/X86/fcmp-logic.ll
index 2b85f3882b704..656bf8d53a5a2 100644
--- a/llvm/test/CodeGen/X86/fcmp-logic.ll
+++ b/llvm/test/CodeGen/X86/fcmp-logic.ll
@@ -341,10 +341,10 @@ define i1 @f32cmp3(float %x, float %y, float %z, float %w) {
; SSE2-NEXT: cmpltss %xmm1, %xmm5
; SSE2-NEXT: cmpltss %xmm0, %xmm4
; SSE2-NEXT: orps %xmm5, %xmm4
-; SSE2-NEXT: movd %xmm4, %ecx
-; SSE2-NEXT: ucomiss %xmm2, %xmm3
-; SSE2-NEXT: seta %al
-; SSE2-NEXT: xorb %cl, %al
+; SSE2-NEXT: cmpltss %xmm3, %xmm2
+; SSE2-NEXT: xorps %xmm4, %xmm2
+; SSE2-NEXT: movd %xmm2, %eax
+; SSE2-NEXT: # kill: def $al killed $al killed $eax
; SSE2-NEXT: retq
;
; AVX1-LABEL: f32cmp3:
@@ -353,10 +353,10 @@ define i1 @f32cmp3(float %x, float %y, float %z, float %w) {
; AVX1-NEXT: vcmpltss %xmm1, %xmm4, %xmm1
; AVX1-NEXT: vcmpltss %xmm0, %xmm4, %xmm0
; AVX1-NEXT: vorps %xmm1, %xmm0, %xmm0
-; AVX1-NEXT: vmovd %xmm0, %ecx
-; AVX1-NEXT: vucomiss %xmm2, %xmm3
-; AVX1-NEXT: seta %al
-; AVX1-NEXT: xorb %cl, %al
+; AVX1-NEXT: vcmpltss %xmm3, %xmm2, %xmm1
+; AVX1-NEXT: vxorps %xmm1, %xmm0, %xmm0
+; AVX1-NEXT: vmovd %xmm0, %eax
+; AVX1-NEXT: # kill: def $al killed $al killed $eax
; AVX1-NEXT: retq
;
; AVX512-LABEL: f32cmp3:
@@ -365,10 +365,10 @@ define i1 @f32cmp3(float %x, float %y, float %z, float %w) {
; AVX512-NEXT: vcmpltss %xmm1, %xmm4, %k0
; AVX512-NEXT: vcmpltss %xmm0, %xmm4, %k1
; AVX512-NEXT: korw %k0, %k1, %k0
-; AVX512-NEXT: kmovw %k0, %ecx
-; AVX512-NEXT: vucomiss %xmm2, %xmm3
-; AVX512-NEXT: seta %al
-; AVX512-NEXT: xorb %cl, %al
+; AVX512-NEXT: vcmpltss %xmm3, %xmm2, %k1
+; AVX512-NEXT: kxorw %k1, %k0, %k0
+; AVX512-NEXT: kmovw %k0, %eax
+; AVX512-NEXT: # kill: def $al killed $al killed $eax
; AVX512-NEXT: retq
%cmpx = fcmp ogt float %x, 0.0
%cmpy = fcmp ogt float %y, 0.0
@@ -675,52 +675,46 @@ define i1 @olt_icmp_ole_and_f64_use(double %w, double %x, double %y, double %z,
define i1 @ogt_and5_f32(float %a, float %b, float %c, float %d, float %e, float %f) {
; SSE2-LABEL: ogt_and5_f32:
; SSE2: # %bb.0:
-; SSE2-NEXT: ucomiss %xmm2, %xmm0
-; SSE2-NEXT: seta %al
-; SSE2-NEXT: cmpltss %xmm0, %xmm3
-; SSE2-NEXT: cmpltss %xmm0, %xmm1
-; SSE2-NEXT: andps %xmm3, %xmm1
-; SSE2-NEXT: movd %xmm1, %ecx
-; SSE2-NEXT: andb %al, %cl
; SSE2-NEXT: cmpltss %xmm0, %xmm5
; SSE2-NEXT: cmpltss %xmm0, %xmm4
; SSE2-NEXT: andps %xmm5, %xmm4
-; SSE2-NEXT: movd %xmm4, %eax
-; SSE2-NEXT: andb %cl, %al
+; SSE2-NEXT: cmpltss %xmm0, %xmm3
+; SSE2-NEXT: cmpltss %xmm0, %xmm1
+; SSE2-NEXT: andps %xmm3, %xmm1
+; SSE2-NEXT: andps %xmm4, %xmm1
+; SSE2-NEXT: cmpltss %xmm0, %xmm2
+; SSE2-NEXT: andps %xmm1, %xmm2
+; SSE2-NEXT: movd %xmm2, %eax
; SSE2-NEXT: # kill: def $al killed $al killed $eax
; SSE2-NEXT: retq
;
; AVX1-LABEL: ogt_and5_f32:
; AVX1: # %bb.0:
-; AVX1-NEXT: vucomiss %xmm2, %xmm0
-; AVX1-NEXT: seta %al
-; AVX1-NEXT: vcmpltss %xmm0, %xmm3, %xmm2
+; AVX1-NEXT: vcmpltss %xmm0, %xmm5, %xmm5
+; AVX1-NEXT: vcmpltss %xmm0, %xmm4, %xmm4
+; AVX1-NEXT: vandps %xmm5, %xmm4, %xmm4
+; AVX1-NEXT: vcmpltss %xmm0, %xmm3, %xmm3
; AVX1-NEXT: vcmpltss %xmm0, %xmm1, %xmm1
-; AVX1-NEXT: vandps %xmm2, %xmm1, %xmm1
-; AVX1-NEXT: vmovd %xmm1, %ecx
-; AVX1-NEXT: andb %al, %cl
-; AVX1-NEXT: vcmpltss %xmm0, %xmm5, %xmm1
-; AVX1-NEXT: vcmpltss %xmm0, %xmm4, %xmm0
-; AVX1-NEXT: vandps %xmm1, %xmm0, %xmm0
+; AVX1-NEXT: vandps %xmm1, %xmm3, %xmm1
+; AVX1-NEXT: vandps %xmm1, %xmm4, %xmm1
+; AVX1-NEXT: vcmpltss %xmm0, %xmm2, %xmm0
+; AVX1-NEXT: vandps %xmm0, %xmm1, %xmm0
; AVX1-NEXT: vmovd %xmm0, %eax
-; AVX1-NEXT: andb %cl, %al
; AVX1-NEXT: # kill: def $al killed $al killed $eax
; AVX1-NEXT: retq
;
; AVX512-LABEL: ogt_and5_f32:
; AVX512: # %bb.0:
-; AVX512-NEXT: vucomiss %xmm2, %xmm0
-; AVX512-NEXT: seta %al
-; AVX512-NEXT: vcmpltss %xmm0, %xmm3, %k0
-; AVX512-NEXT: vcmpltss %xmm0, %xmm1, %k1
-; AVX512-NEXT: kandw %k0, %k1, %k0
-; AVX512-NEXT: kmovw %k0, %ecx
-; AVX512-NEXT: andb %al, %cl
; AVX512-NEXT: vcmpltss %xmm0, %xmm5, %k0
; AVX512-NEXT: vcmpltss %xmm0, %xmm4, %k1
; AVX512-NEXT: kandw %k0, %k1, %k0
+; AVX512-NEXT: vcmpltss %xmm0, %xmm3, %k1
+; AVX512-NEXT: kandw %k1, %k0, %k0
+; AVX512-NEXT: vcmpltss %xmm0, %xmm1, %k1
+; AVX512-NEXT: kandw %k1, %k0, %k0
+; AVX512-NEXT: vcmpltss %xmm0, %xmm2, %k1
+; AVX512-NEXT: kandw %k1, %k0, %k0
; AVX512-NEXT: kmovw %k0, %eax
-; AVX512-NEXT: andb %cl, %al
; AVX512-NEXT: # kill: def $al killed $al killed $eax
; AVX512-NEXT: retq
%c1 = fcmp ogt float %a, %b
@@ -738,52 +732,46 @@ define i1 @ogt_and5_f32(float %a, float %b, float %c, float %d, float %e, float
define i1 @mixed_and5_f32(float %a, float %b, float %c, float %d, float %e, float %f) {
; SSE2-LABEL: mixed_and5_f32:
; SSE2: # %bb.0:
-; SSE2-NEXT: ucomiss %xmm0, %xmm2
-; SSE2-NEXT: seta %al
-; SSE2-NEXT: cmpeqss %xmm0, %xmm3
-; SSE2-NEXT: cmpltss %xmm0, %xmm1
-; SSE2-NEXT: andps %xmm3, %xmm1
-; SSE2-NEXT: movd %xmm1, %ecx
-; SSE2-NEXT: andb %al, %cl
; SSE2-NEXT: cmpless %xmm0, %xmm5
; SSE2-NEXT: cmpneqss %xmm0, %xmm4
; SSE2-NEXT: andps %xmm5, %xmm4
-; SSE2-NEXT: movd %xmm4, %eax
-; SSE2-NEXT: andb %cl, %al
+; SSE2-NEXT: cmpeqss %xmm0, %xmm3
+; SSE2-NEXT: cmpltss %xmm0, %xmm1
+; SSE2-NEXT: andps %xmm3, %xmm1
+; SSE2-NEXT: andps %xmm4, %xmm1
+; SSE2-NEXT: cmpltss %xmm2, %xmm0
+; SSE2-NEXT: andps %xmm1, %xmm0
+; SSE2-NEXT: movd %xmm0, %eax
; SSE2-NEXT: # kill: def $al killed $al killed $eax
; SSE2-NEXT: retq
;
; AVX1-LABEL: mixed_and5_f32:
; AVX1: # %bb.0:
-; AVX1-NEXT: vucomiss %xmm0, %xmm2
-; AVX1-NEXT: seta %al
-; AVX1-NEXT: vcmpeqss %xmm3, %xmm0, %xmm2
+; AVX1-NEXT: vcmpless %xmm0, %xmm5, %xmm5
+; AVX1-NEXT: vcmpneqss %xmm4, %xmm0, %xmm4
+; AVX1-NEXT: vandps %xmm5, %xmm4, %xmm4
+; AVX1-NEXT: vcmpeqss %xmm3, %xmm0, %xmm3
; AVX1-NEXT: vcmpltss %xmm0, %xmm1, %xmm1
-; AVX1-NEXT: vandps %xmm2, %xmm1, %xmm1
-; AVX1-NEXT: vmovd %xmm1, %ecx
-; AVX1-NEXT: andb %al, %cl
-; AVX1-NEXT: vcmpless %xmm0, %xmm5, %xmm1
-; AVX1-NEXT: vcmpneqss %xmm4, %xmm0, %xmm0
-; AVX1-NEXT: vandps %xmm1, %xmm0, %xmm0
+; AVX1-NEXT: vandps %xmm1, %xmm3, %xmm1
+; AVX1-NEXT: vandps %xmm1, %xmm4, %xmm1
+; AVX1-NEXT: vcmpltss %xmm2, %xmm0, %xmm0
+; AVX1-NEXT: vandps %xmm0, %xmm1, %xmm0
; AVX1-NEXT: vmovd %xmm0, %eax
-; AVX1-NEXT: andb %cl, %al
; AVX1-NEXT: # kill: def $al killed $al killed $eax
; AVX1-NEXT: retq
;
; AVX512-LABEL: mixed_and5_f32:
; AVX512: # %bb.0:
-; AVX512-NEXT: vucomiss %xmm0, %xmm2
-; AVX512-NEXT: seta %al
-; AVX512-NEXT: vcmpeqss %xmm3, %xmm0, %k0
-; AVX512-NEXT: vcmpltss %xmm0, %xmm1, %k1
-; AVX512-NEXT: kandw %k0, %k1, %k0
-; AVX512-NEXT: kmovw %k0, %ecx
-; AVX512-NEXT: andb %al, %cl
; AVX512-NEXT: vcmpless %xmm0, %xmm5, %k0
; AVX512-NEXT: vcmpneqss %xmm4, %xmm0, %k1
; AVX512-NEXT: kandw %k0, %k1, %k0
+; AVX512-NEXT: vcmpeqss %xmm3, %xmm0, %k1
+; AVX512-NEXT: kandw %k1, %k0, %k0
+; AVX512-NEXT: vcmpltss %xmm0, %xmm1, %k1
+; AVX512-NEXT: kandw %k1, %k0, %k0
+; AVX512-NEXT: vcmpltss %xmm2, %xmm0, %k1
+; AVX512-NEXT: kandw %k1, %k0, %k0
; AVX512-NEXT: kmovw %k0, %eax
-; AVX512-NEXT: andb %cl, %al
; AVX512-NEXT: # kill: def $al killed $al killed $eax
; AVX512-NEXT: retq
%c1 = fcmp ogt float %a, %b
@@ -801,52 +789,46 @@ define i1 @mixed_and5_f32(float %a, float %b, float %c, float %d, float %e, floa
define i1 @mixed_or5_f64(double %a, double %b, double %c, double %d, double %e, double %f) {
; SSE2-LABEL: mixed_or5_f64:
; SSE2: # %bb.0:
-; SSE2-NEXT: ucomisd %xmm0, %xmm2
-; SSE2-NEXT: seta %al
+; SSE2-NEXT: cmplepd %xmm0, %xmm5
+; SSE2-NEXT: cmpneqpd %xmm0, %xmm4
+; SSE2-NEXT: orpd %xmm5, %xmm4
; SSE2-NEXT: cmpeqsd %xmm0, %xmm3
; SSE2-NEXT: cmpltsd %xmm0, %xmm1
; SSE2-NEXT: orpd %xmm3, %xmm1
-; SSE2-NEXT: movd %xmm1, %ecx
-; SSE2-NEXT: orb %al, %cl
-; SSE2-NEXT: cmplesd %xmm0, %xmm5
-; SSE2-NEXT: cmpneqsd %xmm0, %xmm4
-; SSE2-NEXT: orpd %xmm5, %xmm4
-; SSE2-NEXT: movd %xmm4, %eax
-; SSE2-NEXT: orb %cl, %al
+; SSE2-NEXT: orpd %xmm4, %xmm1
+; SSE2-NEXT: cmpltsd %xmm2, %xmm0
+; SSE2-NEXT: orpd %xmm1, %xmm0
+; SSE2-NEXT: movd %xmm0, %eax
; SSE2-NEXT: # kill: def $al killed $al killed $eax
; SSE2-NEXT: retq
;
; AVX1-LABEL: mixed_or5_f64:
; AVX1: # %bb.0:
-; AVX1-NEXT: vucomisd %xmm0, %xmm2
-; AVX1-NEXT: seta %al
-; AVX1-NEXT: vcmpeqsd %xmm3, %xmm0, %xmm2
+; AVX1-NEXT: vcmplepd %xmm0, %xmm5, %xmm5
+; AVX1-NEXT: vcmpneqpd %xmm4, %xmm0, %xmm4
+; AVX1-NEXT: vorpd %xmm5, %xmm4, %xmm4
+; AVX1-NEXT: vcmpeqsd %xmm3, %xmm0, %xmm3
; AVX1-NEXT: vcmpltsd %xmm0, %xmm1, %xmm1
-; AVX1-NEXT: vorpd %xmm2, %xmm1, %xmm1
-; AVX1-NEXT: vmovd %xmm1, %ecx
-; AVX1-NEXT: orb %al, %cl
-; AVX1-NEXT: vcmplesd %xmm0, %xmm5, %xmm1
-; AVX1-NEXT: vcmpneqsd %xmm4, %xmm0, %xmm0
-; AVX1-NEXT: vorpd %xmm1, %xmm0, %xmm0
+; AVX1-NEXT: vorpd %xmm1, %xmm3, %xmm1
+; AVX1-NEXT: vorpd %xmm1, %xmm4, %xmm1
+; AVX1-NEXT: vcmpltsd %xmm2, %xmm0, %xmm0
+; AVX1-NEXT: vorpd %xmm0, %xmm1, %xmm0
; AVX1-NEXT: vmovd %xmm0, %eax
-; AVX1-NEXT: orb %cl, %al
; AVX1-NEXT: # kill: def $al killed $al killed $eax
; AVX1-NEXT: retq
;
; AVX512-LABEL: mixed_or5_f64:
; AVX512: # %bb.0:
-; AVX512-NEXT: vucomisd %xmm0, %xmm2
-; AVX512-NEXT: seta %al
-; AVX512-NEXT: vcmpeqsd %xmm3, %xmm0, %k0
-; AVX512-NEXT: vcmpltsd %xmm0, %xmm1, %k1
-; AVX512-NEXT: korw %k0, %k1, %k0
-; AVX512-NEXT: kmovw %k0, %ecx
-; AVX512-NEXT: orb %al, %cl
; AVX512-NEXT: vcmplesd %xmm0, %xmm5, %k0
; AVX512-NEXT: vcmpneqsd %xmm4, %xmm0, %k1
; AVX512-NEXT: korw %k0, %k1, %k0
+; AVX512-NEXT: vcmpeqsd %xmm3, %xmm0, %k1
+; AVX512-NEXT: korw %k1, %k0, %k0
+; AVX512-NEXT: vcmpltsd %xmm0, %xmm1, %k1
+; AVX512-NEXT: korw %k1, %k0, %k0
+; AVX512-NEXT: vcmpltsd %xmm2, %xmm0, %k1
+; AVX512-NEXT: korw %k1, %k0, %k0
; AVX512-NEXT: kmovw %k0, %eax
-; AVX512-NEXT: orb %cl, %al
; AVX512-NEXT: # kill: def $al killed $al killed $eax
; AVX512-NEXT: retq
%c1 = fcmp ogt double %a, %b
@@ -865,29 +847,27 @@ define i1 @mixed_or5_f64(double %a, double %b, double %c, double %d, double %e,
define i1 @olt_icmp_ole_oge_and_f64(double %w, double %x, double %y, double %z, i32 %a, i32 %b) {
; SSE2-LABEL: olt_icmp_ole_oge_and_f64:
; SSE2: # %bb.0:
-; SSE2-NEXT: ucomisd %xmm0, %xmm1
-; SSE2-NEXT: seta %al
; SSE2-NEXT: cmpl %esi, %edi
; SSE2-NEXT: setg %cl
-; SSE2-NEXT: andb %al, %cl
; SSE2-NEXT: cmplesd %xmm3, %xmm2
; SSE2-NEXT: cmplesd %xmm0, %xmm3
; SSE2-NEXT: andpd %xmm2, %xmm3
-; SSE2-NEXT: movd %xmm3, %eax
+; SSE2-NEXT: cmpltsd %xmm1, %xmm0
+; SSE2-NEXT: andpd %xmm3, %xmm0
+; SSE2-NEXT: movd %xmm0, %eax
; SSE2-NEXT: andb %cl, %al
; SSE2-NEXT: # kill: def $al killed $al killed $eax
; SSE2-NEXT: retq
;
; AVX1-LABEL: olt_icmp_ole_oge_and_f64:
; AVX1: # %bb.0:
-; AVX1-NEXT: vucomisd %xmm0, %xmm1
-; AVX1-NEXT: seta %al
; AVX1-NEXT: cmpl %esi, %edi
; AVX1-NEXT: setg %cl
-; AVX1-NEXT: andb %al, %cl
-; AVX1-NEXT: vcmplesd %xmm0, %xmm3, %xmm0
-; AVX1-NEXT: vcmplesd %xmm3, %xmm2, %xmm1
-; AVX1-NEXT: vandpd %xmm0, %xmm1, %xmm0
+; AVX1-NEXT: vcmplesd %xmm0, %xmm3, %xmm4
+; AVX1-NEXT: vcmplesd %xmm3, %xmm2, %xmm2
+; AVX1-NEXT: vandpd %xmm4, %xmm2, %xmm2
+; AVX1-NEXT: vcmpltsd %xmm1, %xmm0, %xmm0
+; AVX1-NEXT: vandpd %xmm0, %xmm2, %xmm0
; AVX1-NEXT: vmovd %xmm0, %eax
; AVX1-NEXT: andb %cl, %al
; AVX1-NEXT: # kill: def $al killed $al killed $eax
@@ -895,14 +875,13 @@ define i1 @olt_icmp_ole_oge_and_f64(double %w, double %x, double %y, double %z,
;
; AVX512-LABEL: olt_icmp_ole_oge_and_f64:
; AVX512: # %bb.0:
-; AVX512-NEXT: vucomisd %xmm0, %xmm1
-; AVX512-NEXT: seta %al
; AVX512-NEXT: cmpl %esi, %edi
; AVX512-NEXT: setg %cl
-; AVX512-NEXT: andb %al, %cl
; AVX512-NEXT: vcmplesd %xmm0, %xmm3, %k0
; AVX512-NEXT: vcmplesd %xmm3, %xmm2, %k1
; AVX512-NEXT: kandw %k0, %k1, %k0
+; AVX512-NEXT: vcmpltsd %xmm1, %xmm0, %k1
+; AVX512-NEXT: kandw %k1, %k0, %k0
; AVX512-NEXT: kmovw %k0, %eax
; AVX512-NEXT: andb %cl, %al
; AVX512-NEXT: # kill: def $al killed $al killed $eax
@@ -920,43 +899,40 @@ define i1 @olt_icmp_ole_oge_and_f64(double %w, double %x, double %y, double %z,
define i1 @olt_ole_and_and_f64(double %a, double %b, double %c, double %d, double %w, double %x, double %y, double %z) {
; SSE2-LABEL: olt_ole_and_and_f64:
; SSE2: # %bb.0:
-; SSE2-NEXT: cmplesd %xmm3, %xmm2
+; SSE2-NEXT: cmpltsd %xmm5, %xmm4
; SSE2-NEXT: cmpltsd %xmm1, %xmm0
-; SSE2-NEXT: andpd %xmm2, %xmm0
+; SSE2-NEXT: andpd %xmm4, %xmm0
; SSE2-NEXT: cmplesd %xmm7, %xmm6
-; SSE2-NEXT: cmpltsd %xmm5, %xmm4
-; SSE2-NEXT: andpd %xmm6, %xmm4
-; SSE2-NEXT: movd %xmm4, %ecx
-; SSE2-NEXT: movd %xmm0, %eax
-; SSE2-NEXT: andl %ecx, %eax
+; SSE2-NEXT: cmplesd %xmm3, %xmm2
+; SSE2-NEXT: andpd %xmm6, %xmm2
+; SSE2-NEXT: andpd %xmm0, %xmm2
+; SSE2-NEXT: movd %xmm2, %eax
; SSE2-NEXT: # kill: def $al killed $al killed $eax
; SSE2-NEXT: retq
;
; AVX1-LABEL: olt_ole_and_and_f64:
; AVX1: # %bb.0:
-; AVX1-NEXT: vcmplesd %xmm3, %xmm2, %xmm2
+; AVX1-NEXT: vcmpltsd %xmm5, %xmm4, %xmm4
; AVX1-NEXT: vcmpltsd %xmm1, %xmm0, %xmm0
-; AVX1-NEXT: vandpd %xmm2, %xmm0, %xmm0
+; AVX1-NEXT: vandpd %xmm0, %xmm4, %xmm0
; AVX1-NEXT: vcmplesd %xmm7, %xmm6, %xmm1
-; AVX1-NEXT: vcmpltsd %xmm5, %xmm4, %xmm2
-; AVX1-NEXT: vandpd %xmm1, %xmm2, %xmm1
-; AVX1-NEXT: vmovd %xmm1, %ecx
+; AVX1-NEXT: vcmplesd %xmm3, %xmm2, %xmm2
+; AVX1-NEXT: vandpd %xmm2, %xmm1, %xmm1
+; AVX1-NEXT: vandpd %xmm1, %xmm0, %xmm0
; AVX1-NEXT: vmovd %xmm0, %eax
-; AVX1-NEXT: andl %ecx, %eax
; AVX1-NEXT: # kill: def $al killed $al killed $eax
; AVX1-NEXT: retq
;
; AVX512-LABEL: olt_ole_and_and_f64:
; AVX512: # %bb.0:
-; AVX512-NEXT: vcmplesd %xmm3, %xmm2, %k0
-; AVX512-NEXT: vcmpltsd %xmm1, %xmm0, %k1
-; AVX512-NEXT: kandw %k0, %k1, %k0
-; AVX512-NEXT: kmovw %k0, %ecx
-; AVX512-NEXT: vcmplesd %xmm7, %xmm6, %k0
+; AVX512-NEXT: vcmpltsd %xmm1, %xmm0, %k0
; AVX512-NEXT: vcmpltsd %xmm5, %xmm4, %k1
; AVX512-NEXT: kandw %k0, %k1, %k0
+; AVX512-NEXT: vcmplesd %xmm7, %xmm6, %k1
+; AVX512-NEXT: kandw %k1, %k0, %k0
+; AVX512-NEXT: vcmplesd %xmm3, %xmm2, %k1
+; AVX512-NEXT: kandw %k1, %k0, %k0
; AVX512-NEXT: kmovw %k0, %eax
-; AVX512-NEXT: andb %cl, %al
; AVX512-NEXT: # kill: def $al killed $al killed $eax
; AVX512-NEXT: retq
%f1 = fcmp olt double %a, %b
@@ -972,52 +948,46 @@ define i1 @olt_ole_and_and_f64(double %a, double %b, double %c, double %d, doubl
define i1 @mixed_xor5_f32(float %a, float %b, float %c, float %d, float %e, float %f) {
; SSE2-LABEL: mixed_xor5_f32:
; SSE2: # %bb.0:
-; SSE2-NEXT: ucomiss %xmm0, %xmm2
-; SSE2-NEXT: seta %al
-; SSE2-NEXT: cmpeqss %xmm0, %xmm3
-; SSE2-NEXT: cmpltss %xmm0, %xmm1
-; SSE2-NEXT: xorps %xmm3, %xmm1
-; SSE2-NEXT: movd %xmm1, %ecx
-; SSE2-NEXT: xorb %al, %cl
; SSE2-NEXT: cmpless %xmm0, %xmm5
; SSE2-NEXT: cmpneqss %xmm0, %xmm4
; SSE2-NEXT: xorps %xmm5, %xmm4
-; SSE2-NEXT: movd %xmm4, %eax
-; SSE2-NEXT: xorb %cl, %al
+; SSE2-NEXT: cmpeqss %xmm0, %xmm3
+; SSE2-NEXT: cmpltss %xmm0, %xmm1
+; SSE2-NEXT: xorps %xmm3, %xmm1
+; SSE2-NEXT: xorps %xmm4, %xmm1
+; SSE2-NEXT: cmpltss %xmm2, %xmm0
+; SSE2-NEXT: xorps %xmm1, %xmm0
+; SSE2-NEXT: movd %xmm0, %eax
; SSE2-NEXT: # kill: def $al killed $al killed $eax
; SSE2-NEXT: retq
;
; AVX1-LABEL: mixed_xor5_f32:
; AVX1: # %bb.0:
-; AVX1-NEXT: vucomiss %xmm0, %xmm2
-; AVX1-NEXT: seta %al
-; AVX1-NEXT: vcmpeqss %xmm3, %xmm0, %xmm2
+; AVX1-NEXT: vcmpless %xmm0, %xmm5, %xmm5
+; AVX1-NEXT: vcmpneqss %xmm4, %xmm0, %xmm4
+; AVX1-NEXT: vxorps %xmm5, %xmm4, %xmm4
+; AVX1-NEXT: vcmpeqss %xmm3, %xmm0, %xmm3
; AVX1-NEXT: vcmpltss %xmm0, %xmm1, %xmm1
-; AVX1-NEXT: vxorps %xmm2, %xmm1, %xmm1
-; AVX1-NEXT: vmovd %xmm1, %ecx
-; AVX1-NEXT: xorb %al, %cl
-; AVX1-NEXT: vcmpless %xmm0, %xmm5, %xmm1
-; AVX1-NEXT: vcmpneqss %xmm4, %xmm0, %xmm0
-; AVX1-NEXT: vxorps %xmm1, %xmm0, %xmm0
+; AVX1-NEXT: vxorps %xmm1, %xmm3, %xmm1
+; AVX1-NEXT: vxorps %xmm1, %xmm4, %xmm1
+; AVX1-NEXT: vcmpltss %xmm2, %xmm0, %xmm0
+; AVX1-NEXT: vxorps %xmm0, %xmm1, %xmm0
; AVX1-NEXT: vmovd %xmm0, %eax
-; AVX1-NEXT: xorb %cl, %al
; AVX1-NEXT: # kill: def $al killed $al killed $eax
; AVX1-NEXT: retq
;
; AVX512-LABEL: mixed_xor5_f32:
; AVX512: # %bb.0:
-; AVX512-NEXT: vucomiss %xmm0, %xmm2
-; AVX512-NEXT: seta %al
-; AVX512-NEXT: vcmpeqss %xmm3, %xmm0, %k0
-; AVX512-NEXT: vcmpltss %xmm0, %xmm1, %k1
-; AVX512-NEXT: kxorw %k0, %k1, %k0
-; AVX512-NEXT: kmovw %k0, %ecx
-; AVX512-NEXT: xorb %al, %cl
; AVX512-NEXT: vcmpless %xmm0, %xmm5, %k0
; AVX512-NEXT: vcmpneqss %xmm4, %xmm0, %k1
; AVX512-NEXT: kxorw %k0, %k1, %k0
+; AVX512-NEXT: vcmpeqss %xmm3, %xmm0, %k1
+; AVX512-NEXT: kxorw %k1, %k0, %k0
+; AVX512-NEXT: vcmpltss %xmm0, %xmm1, %k1
+; AVX512-NEXT: kxorw %k1, %k0, %k0
+; AVX512-NEXT: vcmpltss %xmm2, %xmm0, %k1
+; AVX512-NEXT: kxorw %k1, %k0, %k0
; AVX512-NEXT: kmovw %k0, %eax
-; AVX512-NEXT: xorb %cl, %al
; AVX512-NEXT: # kill: def $al killed $al killed $eax
; AVX512-NEXT: retq
%c1 = fcmp ogt float %a, %b
@@ -1036,35 +1006,35 @@ define i1 @olt_and10_f64(double %a, double %b0, double %b1, double %b2, double %
; SSE2-LABEL: olt_and10_f64:
; SSE2: # %bb.0:
; SSE2-NEXT: movapd %xmm0, %xmm8
-; SSE2-NEXT: cmpltsd %xmm2, %xmm8
-; SSE2-NEXT: movapd %xmm0, %xmm2
-; SSE2-NEXT: cmpltsd %xmm1, %xmm2
-; SSE2-NEXT: andpd %xmm8, %xmm2
-; SSE2-NEXT: movd %xmm2, %eax
+; SSE2-NEXT: cmpltsd %xmm4, %xmm8
+; SSE2-NEXT: movapd %xmm0, %xmm4
+; SSE2-NEXT: cmpltsd %xmm3, %xmm4
+; SSE2-NEXT: andpd %xmm8, %xmm4
+; SSE2-NEXT: movapd %xmm0, %xmm3
+; SSE2-NEXT: cmpltsd %xmm1, %xmm3
; SSE2-NEXT: movapd %xmm0, %xmm1
-; SSE2-NEXT: cmpltsd %xmm4, %xmm1
+; SSE2-NEXT: cmpltsd %xmm2, %xmm1
+; SSE2-NEXT: andpd %xmm3, %xmm1
+; SSE2-NEXT: andpd %xmm4, %xmm1
+; SSE2-NEXT: movd %xmm1, %ecx
+; SSE2-NEXT: movsd {{.*#+}} xmm1 = mem[0],zero
; SSE2-NEXT: movapd %xmm0, %xmm2
-; SSE2-NEXT: cmpltsd %xmm3, %xmm2
-; SSE2-NEXT: andpd %xmm1, %xmm2
-; SSE2-NEXT: movd %xmm2, %ecx
-; SSE2-NEXT: andl %eax, %ecx
-; SSE2-NEXT: movapd %xmm0, %xmm1
-; SSE2-NEXT: cmpltsd %xmm6, %xmm1
+; SSE2-NEXT: cmpltpd %xmm1, %xmm2
+; SSE2-NEXT: movsd {{.*#+}} xmm1 = mem[0],zero
+; SSE2-NEXT: movapd %xmm0, %xmm3
+; SSE2-NEXT: cmpltpd %xmm1, %xmm3
+; SSE2-NEXT: andpd %xmm2, %xmm3
+; SSE2-NEXT: movsd {{.*#+}} xmm1 = mem[0],zero
; SSE2-NEXT: movapd %xmm0, %xmm2
-; SSE2-NEXT: cmpltsd %xmm5, %xmm2
-; SSE2-NEXT: andpd %xmm1, %xmm2
-; SSE2-NEXT: movd %xmm2, %eax
-; SSE2-NEXT: andl %ecx, %eax
+; SSE2-NEXT: cmpltpd %xmm1, %xmm2
; SSE2-NEXT: movapd %xmm0, %xmm1
; SSE2-NEXT: cmpltsd %xmm7, %xmm1
+; SSE2-NEXT: andpd %xmm2, %xmm1
+; SSE2-NEXT: andpd %xmm3, %xmm1
; SSE2-NEXT: movapd %xmm0, %xmm2
-; SSE2-NEXT: cmpltsd {{[0-9]+}}(%rsp), %xmm2
-; SSE2-NEXT: andpd %xmm1, %xmm2
-; SSE2-NEXT: movd %xmm2, %ecx
-; SSE2-NEXT: andl %eax, %ecx
-; SSE2-NEXT: movapd %xmm0, %xmm1
-; SSE2-NEXT: cmpltsd {{[0-9]+}}(%rsp), %xmm1
-; SSE2-NEXT: cmpltsd {{[0-9]+}}(%rsp), %xmm0
+; SSE2-NEXT: cmpltsd %xmm6, %xmm2
+; SSE2-NEXT: cmpltsd %xmm5, %xmm0
+; SSE2-NEXT: andpd %xmm2, %xmm0
; SSE2-NEXT: andpd %xmm1, %xmm0
; SSE2-NEXT: movd %xmm0, %eax
; SSE2-NEXT: andl %ecx, %eax
@@ -1073,28 +1043,28 @@ define i1 @olt_and10_f64(double %a, double %b0, double %b1, double %b2, double %
;
; AVX1-LABEL: olt_and10_f64:
; AVX1: # %bb.0:
-; AVX1-NEXT: vcmpltsd %xmm2, %xmm0, %xmm2
+; AVX1-NEXT: vcmpltsd %xmm4, %xmm0, %xmm4
+; AVX1-NEXT: vcmpltsd %xmm3, %xmm0, %xmm3
+; AVX1-NEXT: vandpd %xmm4, %xmm3, %xmm3
; AVX1-NEXT: vcmpltsd %xmm1, %xmm0, %xmm1
+; AVX1-NEXT: vcmpltsd %xmm2, %xmm0, %xmm2
; AVX1-NEXT: vandpd %xmm2, %xmm1, %xmm1
-; AVX1-NEXT: vmovd %xmm1, %eax
-; AVX1-NEXT: vcmpltsd %xmm4, %xmm0, %xmm1
-; AVX1-NEXT: vcmpltsd %xmm3, %xmm0, %xmm2
-; AVX1-NEXT: vandpd %xmm1, %xmm2, %xmm1
+; AVX1-NEXT: vandpd %xmm1, %xmm3, %xmm1
; AVX1-NEXT: vmovd %xmm1, %ecx
-; AVX1-NEXT: andl %eax, %ecx
-; AVX1-NEXT: vcmpltsd %xmm6, %xmm0, %xmm1
-; AVX1-NEXT: vcmpltsd %xmm5, %xmm0, %xmm2
+; AVX1-NEXT: vmovsd {{.*#+}} xmm1 = mem[0],zero
+; AVX1-NEXT: vcmpltpd %xmm1, %xmm0, %xmm1
+; AVX1-NEXT: vmovsd {{.*#+}} xmm2 = mem[0],zero
+; AVX1-NEXT: vcmpltpd %xmm2, %xmm0, %xmm2
; AVX1-NEXT: vandpd %xmm1, %xmm2, %xmm1
-; AVX1-NEXT: vmovd %xmm1, %eax
-; AVX1-NEXT: andl %ecx, %eax
-; AVX1-NEXT: vcmpltsd %xmm7, %xmm0, %xmm1
-; AVX1-NEXT: vcmpltsd {{[0-9]+}}(%rsp), %xmm0, %xmm2
+; AVX1-NEXT: vmovsd {{.*#+}} xmm2 = mem[0],zero
+; AVX1-NEXT: vcmpltpd %xmm2, %xmm0, %xmm2
+; AVX1-NEXT: vcmpltsd %xmm7, %xmm0, %xmm3
+; AVX1-NEXT: vandpd %xmm3, %xmm2, %xmm2
; AVX1-NEXT: vandpd %xmm2, %xmm1, %xmm1
-; AVX1-NEXT: vmovd %xmm1, %ecx
-; AVX1-NEXT: andl %eax, %ecx
-; AVX1-NEXT: vcmpltsd {{[0-9]+}}(%rsp), %xmm0, %xmm1
-; AVX1-NEXT: vcmpltsd {{[0-9]+}}(%rsp), %xmm0, %xmm0
-; AVX1-NEXT: vandpd %xmm1, %xmm0, %xmm0
+; AVX1-NEXT: vcmpltsd %xmm6, %xmm0, %xmm2
+; AVX1-NEXT: vcmpltsd %xmm5, %xmm0, %xmm0
+; AVX1-NEXT: vandpd %xmm0, %xmm2, %xmm0
+; AVX1-NEXT: vandpd %xmm0, %xmm1, %xmm0
; AVX1-NEXT: vmovd %xmm0, %eax
; AVX1-NEXT: andl %ecx, %eax
; AVX1-NEXT: # kill: def $al killed $al killed $eax
@@ -1102,28 +1072,25 @@ define i1 @olt_and10_f64(double %a, double %b0, double %b1, double %b2, double %
;
; AVX512-LABEL: olt_and10_f64:
; AVX512: # %bb.0:
-; AVX512-NEXT: vcmpltsd %xmm2, %xmm0, %k0
-; AVX512-NEXT: vcmpltsd %xmm1, %xmm0, %k1
-; AVX512-NEXT: kandw %k0, %k1, %k0
-; AVX512-NEXT: kmovw %k0, %eax
; AVX512-NEXT: vcmpltsd %xmm4, %xmm0, %k0
; AVX512-NEXT: vcmpltsd %xmm3, %xmm0, %k1
; AVX512-NEXT: kandw %k0, %k1, %k0
-; AVX512-NEXT: kmovw %k0, %ecx
-; AVX512-NEXT: andb %al, %cl
-; AVX512-NEXT: vcmpltsd %xmm6, %xmm0, %k0
-; AVX512-NEXT: vcmpltsd %xmm5, %xmm0, %k1
-; AVX512-NEXT: kandw %k0, %k1, %k0
-; AVX512-NEXT: kmovw %k0, %eax
-; AVX512-NEXT: andb %cl, %al
-; AVX512-NEXT: vcmpltsd %xmm7, %xmm0, %k0
-; AVX512-NEXT: vcmpltsd {{[0-9]+}}(%rsp), %xmm0, %k1
+; AVX512-NEXT: vcmpltsd %xmm1, %xmm0, %k1
+; AVX512-NEXT: kandw %k1, %k0, %k0
+; AVX512-NEXT: vcmpltsd %xmm2, %xmm0, %k1
; AVX512-NEXT: kandw %k1, %k0, %k0
; AVX512-NEXT: kmovw %k0, %ecx
-; AVX512-NEXT: andb %al, %cl
-; AVX512-NEXT: vcmpltsd {{[0-9]+}}(%rsp), %xmm0, %k0
+; AVX512-NEXT: vcmpltsd %xmm7, %xmm0, %k0
; AVX512-NEXT: vcmpltsd {{[0-9]+}}(%rsp), %xmm0, %k1
+; AVX512-NEXT: vcmpltsd {{[0-9]+}}(%rsp), %xmm0, %k2
+; AVX512-NEXT: kandw %k1, %k2, %k1
+; AVX512-NEXT: vcmpltsd {{[0-9]+}}(%rsp), %xmm0, %k2
+; AVX512-NEXT: kandw %k2, %k1, %k1
; AVX512-NEXT: kandw %k0, %k1, %k0
+; AVX512-NEXT: vcmpltsd %xmm6, %xmm0, %k1
+; AVX512-NEXT: kandw %k1, %k0, %k0
+; AVX512-NEXT: vcmpltsd %xmm5, %xmm0, %k1
+; AVX512-NEXT: kandw %k1, %k0, %k0
; AVX512-NEXT: kmovw %k0, %eax
; AVX512-NEXT: andb %cl, %al
; AVX512-NEXT: # kill: def $al killed $al killed $eax
@@ -1154,98 +1121,94 @@ define i1 @olt_and10_f64(double %a, double %b0, double %b1, double %b2, double %
define i1 @olt_and5_and5_f64(double %a, double %b0, double %b1, double %b2, double %b3, double %b4, double %b5, double %b6, double %b7, double %b8, double %b9) {
; SSE2-LABEL: olt_and5_and5_f64:
; SSE2: # %bb.0:
-; SSE2-NEXT: ucomisd %xmm0, %xmm2
-; SSE2-NEXT: seta %al
-; SSE2-NEXT: ucomisd %xmm0, %xmm7
-; SSE2-NEXT: seta %cl
-; SSE2-NEXT: movapd %xmm0, %xmm2
-; SSE2-NEXT: cmpltsd %xmm3, %xmm2
+; SSE2-NEXT: movapd %xmm0, %xmm8
+; SSE2-NEXT: cmpltsd %xmm4, %xmm8
+; SSE2-NEXT: movapd %xmm0, %xmm4
+; SSE2-NEXT: cmpltsd %xmm3, %xmm4
+; SSE2-NEXT: andpd %xmm8, %xmm4
; SSE2-NEXT: movapd %xmm0, %xmm3
; SSE2-NEXT: cmpltsd %xmm1, %xmm3
-; SSE2-NEXT: andpd %xmm2, %xmm3
-; SSE2-NEXT: movd %xmm3, %edx
-; SSE2-NEXT: andb %al, %dl
-; SSE2-NEXT: movapd %xmm0, %xmm1
-; SSE2-NEXT: cmpltsd %xmm5, %xmm1
-; SSE2-NEXT: movapd %xmm0, %xmm2
-; SSE2-NEXT: cmpltsd %xmm4, %xmm2
-; SSE2-NEXT: andpd %xmm1, %xmm2
-; SSE2-NEXT: movd %xmm2, %esi
-; SSE2-NEXT: andb %dl, %sil
; SSE2-NEXT: movapd %xmm0, %xmm1
-; SSE2-NEXT: cmpltsd %xmm6, %xmm1
+; SSE2-NEXT: cmpltsd %xmm2, %xmm1
+; SSE2-NEXT: andpd %xmm3, %xmm1
+; SSE2-NEXT: andpd %xmm4, %xmm1
+; SSE2-NEXT: movsd {{.*#+}} xmm2 = mem[0],zero
+; SSE2-NEXT: movapd %xmm0, %xmm3
+; SSE2-NEXT: cmpltpd %xmm2, %xmm3
+; SSE2-NEXT: movsd {{.*#+}} xmm2 = mem[0],zero
+; SSE2-NEXT: movapd %xmm0, %xmm4
+; SSE2-NEXT: cmpltpd %xmm2, %xmm4
+; SSE2-NEXT: andpd %xmm3, %xmm4
+; SSE2-NEXT: movsd {{.*#+}} xmm2 = mem[0],zero
+; SSE2-NEXT: movapd %xmm0, %xmm3
+; SSE2-NEXT: cmpltpd %xmm2, %xmm3
; SSE2-NEXT: movapd %xmm0, %xmm2
-; SSE2-NEXT: cmpltsd {{[0-9]+}}(%rsp), %xmm2
-; SSE2-NEXT: andpd %xmm1, %xmm2
-; SSE2-NEXT: movd %xmm2, %edx
-; SSE2-NEXT: andb %cl, %dl
-; SSE2-NEXT: movapd %xmm0, %xmm1
-; SSE2-NEXT: cmpltsd {{[0-9]+}}(%rsp), %xmm1
-; SSE2-NEXT: cmpltsd {{[0-9]+}}(%rsp), %xmm0
-; SSE2-NEXT: andpd %xmm1, %xmm0
+; SSE2-NEXT: cmpltsd %xmm6, %xmm2
+; SSE2-NEXT: andpd %xmm3, %xmm2
+; SSE2-NEXT: andpd %xmm4, %xmm2
+; SSE2-NEXT: movapd %xmm0, %xmm3
+; SSE2-NEXT: cmpltsd %xmm7, %xmm3
+; SSE2-NEXT: movd %xmm1, %ecx
+; SSE2-NEXT: cmpltsd %xmm5, %xmm0
+; SSE2-NEXT: andpd %xmm3, %xmm0
+; SSE2-NEXT: andpd %xmm2, %xmm0
; SSE2-NEXT: movd %xmm0, %eax
-; SSE2-NEXT: andb %dl, %al
-; SSE2-NEXT: andb %sil, %al
+; SSE2-NEXT: andl %ecx, %eax
; SSE2-NEXT: # kill: def $al killed $al killed $eax
; SSE2-NEXT: retq
;
; AVX1-LABEL: olt_and5_and5_f64:
; AVX1: # %bb.0:
-; AVX1-NEXT: vucomisd %xmm0, %xmm2
-; AVX1-NEXT: seta %al
-; AVX1-NEXT: vucomisd %xmm0, %xmm7
-; AVX1-NEXT: seta %cl
-; AVX1-NEXT: vcmpltsd %xmm3, %xmm0, %xmm2
+; AVX1-NEXT: vcmpltsd %xmm4, %xmm0, %xmm4
+; AVX1-NEXT: vcmpltsd %xmm3, %xmm0, %xmm3
+; AVX1-NEXT: vandpd %xmm4, %xmm3, %xmm3
; AVX1-NEXT: vcmpltsd %xmm1, %xmm0, %xmm1
+; AVX1-NEXT: vcmpltsd %xmm2, %xmm0, %xmm2
; AVX1-NEXT: vandpd %xmm2, %xmm1, %xmm1
-; AVX1-NEXT: vmovd %xmm1, %edx
-; AVX1-NEXT: andb %al, %dl
-; AVX1-NEXT: vcmpltsd %xmm5, %xmm0, %xmm1
-; AVX1-NEXT: vcmpltsd %xmm4, %xmm0, %xmm2
-; AVX1-NEXT: vandpd %xmm1, %xmm2, %xmm1
-; AVX1-NEXT: vmovd %xmm1, %esi
-; AVX1-NEXT: andb %dl, %sil
-; AVX1-NEXT: vcmpltsd %xmm6, %xmm0, %xmm1
-; AVX1-NEXT: vcmpltsd {{[0-9]+}}(%rsp), %xmm0, %xmm2
-; AVX1-NEXT: vandpd %xmm2, %xmm1, %xmm1
-; AVX1-NEXT: vmovd %xmm1, %edx
-; AVX1-NEXT: andb %cl, %dl
-; AVX1-NEXT: vcmpltsd {{[0-9]+}}(%rsp), %xmm0, %xmm1
-; AVX1-NEXT: vcmpltsd {{[0-9]+}}(%rsp), %xmm0, %xmm0
-; AVX1-NEXT: vandpd %xmm1, %xmm0, %xmm0
+; AVX1-NEXT: vandpd %xmm1, %xmm3, %xmm1
+; AVX1-NEXT: vmovsd {{.*#+}} xmm2 = mem[0],zero
+; AVX1-NEXT: vcmpltpd %xmm2, %xmm0, %xmm2
+; AVX1-NEXT: vmovsd {{.*#+}} xmm3 = mem[0],zero
+; AVX1-NEXT: vcmpltpd %xmm3, %xmm0, %xmm3
+; AVX1-NEXT: vandpd %xmm2, %xmm3, %xmm2
+; AVX1-NEXT: vmovsd {{.*#+}} xmm3 = mem[0],zero
+; AVX1-NEXT: vcmpltpd %xmm3, %xmm0, %xmm3
+; AVX1-NEXT: vcmpltsd %xmm6, %xmm0, %xmm4
+; AVX1-NEXT: vandpd %xmm4, %xmm3, %xmm3
+; AVX1-NEXT: vandpd %xmm3, %xmm2, %xmm2
+; AVX1-NEXT: vcmpltsd %xmm7, %xmm0, %xmm3
+; AVX1-NEXT: vmovd %xmm1, %ecx
+; AVX1-NEXT: vcmpltsd %xmm5, %xmm0, %xmm0
+; AVX1-NEXT: vandpd %xmm0, %xmm3, %xmm0
+; AVX1-NEXT: vandpd %xmm0, %xmm2, %xmm0
; AVX1-NEXT: vmovd %xmm0, %eax
-; AVX1-NEXT: andb %dl, %al
-; AVX1-NEXT: andb %sil, %al
+; AVX1-NEXT: andl %ecx, %eax
; AVX1-NEXT: # kill: def $al killed $al killed $eax
; AVX1-NEXT: retq
;
; AVX512-LABEL: olt_and5_and5_f64:
; AVX512: # %bb.0:
-; AVX512-NEXT: vucomisd %xmm0, %xmm2
-; AVX512-NEXT: seta %al
-; AVX512-NEXT: vucomisd %xmm0, %xmm7
-; AVX512-NEXT: seta %cl
-; AVX512-NEXT: vcmpltsd %xmm3, %xmm0, %k0
-; AVX512-NEXT: vcmpltsd %xmm1, %xmm0, %k1
-; AVX512-NEXT: kandw %k0, %k1, %k0
-; AVX512-NEXT: kmovw %k0, %edx
-; AVX512-NEXT: andb %al, %dl
-; AVX512-NEXT: vcmpltsd %xmm5, %xmm0, %k0
-; AVX512-NEXT: vcmpltsd %xmm4, %xmm0, %k1
+; AVX512-NEXT: vcmpltsd %xmm4, %xmm0, %k0
+; AVX512-NEXT: vcmpltsd %xmm3, %xmm0, %k1
; AVX512-NEXT: kandw %k0, %k1, %k0
-; AVX512-NEXT: kmovw %k0, %esi
-; AVX512-NEXT: andb %dl, %sil
-; AVX512-NEXT: vcmpltsd %xmm6, %xmm0, %k0
-; AVX512-NEXT: vcmpltsd {{[0-9]+}}(%rsp), %xmm0, %k1
+; AVX512-NEXT: vcmpltsd %xmm1, %xmm0, %k1
+; AVX512-NEXT: kandw %k1, %k0, %k0
+; AVX512-NEXT: vcmpltsd %xmm2, %xmm0, %k1
; AVX512-NEXT: kandw %k1, %k0, %k0
-; AVX512-NEXT: kmovw %k0, %edx
-; AVX512-NEXT: andb %cl, %dl
-; AVX512-NEXT: vcmpltsd {{[0-9]+}}(%rsp), %xmm0, %k0
+; AVX512-NEXT: kmovw %k0, %ecx
+; AVX512-NEXT: vcmpltsd %xmm6, %xmm0, %k0
; AVX512-NEXT: vcmpltsd {{[0-9]+}}(%rsp), %xmm0, %k1
+; AVX512-NEXT: vcmpltsd {{[0-9]+}}(%rsp), %xmm0, %k2
+; AVX512-NEXT: kandw %k1, %k2, %k1
+; AVX512-NEXT: vcmpltsd {{[0-9]+}}(%rsp), %xmm0, %k2
+; AVX512-NEXT: kandw %k2, %k1, %k1
; AVX512-NEXT: kandw %k0, %k1, %k0
+; AVX512-NEXT: vcmpltsd %xmm7, %xmm0, %k1
+; AVX512-NEXT: kandw %k1, %k0, %k0
+; AVX512-NEXT: vcmpltsd %xmm5, %xmm0, %k1
+; AVX512-NEXT: kandw %k1, %k0, %k0
; AVX512-NEXT: kmovw %k0, %eax
-; AVX512-NEXT: andb %dl, %al
-; AVX512-NEXT: andb %sil, %al
+; AVX512-NEXT: andb %cl, %al
; AVX512-NEXT: # kill: def $al killed $al killed $eax
; AVX512-NEXT: retq
%c0 = fcmp olt double %a, %b0
@@ -1277,30 +1240,28 @@ define i1 @olt_and8_icmp_f64(double %a, double %b0, double %b1, double %b2, doub
; SSE2-NEXT: cmpl %esi, %edi
; SSE2-NEXT: setl %al
; SSE2-NEXT: movapd %xmm0, %xmm8
-; SSE2-NEXT: cmpltsd %xmm2, %xmm8
-; SSE2-NEXT: movapd %xmm0, %xmm2
-; SSE2-NEXT: cmpltsd %xmm1, %xmm2
-; SSE2-NEXT: andpd %xmm8, %xmm2
-; SSE2-NEXT: movd %xmm2, %ecx
-; SSE2-NEXT: movapd %xmm0, %xmm1
-; SSE2-NEXT: cmpltsd %xmm4, %xmm1
-; SSE2-NEXT: movapd %xmm0, %xmm2
-; SSE2-NEXT: cmpltsd %xmm3, %xmm2
-; SSE2-NEXT: andpd %xmm1, %xmm2
-; SSE2-NEXT: movd %xmm2, %edx
-; SSE2-NEXT: andl %ecx, %edx
+; SSE2-NEXT: cmpltsd %xmm4, %xmm8
+; SSE2-NEXT: movapd %xmm0, %xmm4
+; SSE2-NEXT: cmpltsd %xmm3, %xmm4
+; SSE2-NEXT: andpd %xmm8, %xmm4
+; SSE2-NEXT: movapd %xmm0, %xmm3
+; SSE2-NEXT: cmpltsd %xmm1, %xmm3
; SSE2-NEXT: movapd %xmm0, %xmm1
-; SSE2-NEXT: cmpltsd %xmm6, %xmm1
-; SSE2-NEXT: movapd %xmm0, %xmm2
-; SSE2-NEXT: cmpltsd %xmm5, %xmm2
-; SSE2-NEXT: andpd %xmm1, %xmm2
-; SSE2-NEXT: movd %xmm2, %ecx
+; SSE2-NEXT: cmpltsd %xmm2, %xmm1
+; SSE2-NEXT: andpd %xmm3, %xmm1
+; SSE2-NEXT: andpd %xmm4, %xmm1
+; SSE2-NEXT: movd %xmm1, %ecx
; SSE2-NEXT: andb %al, %cl
-; SSE2-NEXT: andb %dl, %cl
; SSE2-NEXT: movapd %xmm0, %xmm1
; SSE2-NEXT: cmpltsd %xmm7, %xmm1
-; SSE2-NEXT: cmpltsd {{[0-9]+}}(%rsp), %xmm0
-; SSE2-NEXT: andpd %xmm1, %xmm0
+; SSE2-NEXT: movapd %xmm0, %xmm2
+; SSE2-NEXT: cmpltsd {{[0-9]+}}(%rsp), %xmm2
+; SSE2-NEXT: movapd %xmm0, %xmm3
+; SSE2-NEXT: cmpltsd %xmm6, %xmm3
+; SSE2-NEXT: andpd %xmm1, %xmm3
+; SSE2-NEXT: cmpltsd %xmm5, %xmm0
+; SSE2-NEXT: andpd %xmm3, %xmm0
+; SSE2-NEXT: andpd %xmm2, %xmm0
; SSE2-NEXT: movd %xmm0, %eax
; SSE2-NEXT: andb %cl, %al
; SSE2-NEXT: # kill: def $al killed $al killed $eax
@@ -1310,24 +1271,22 @@ define i1 @olt_and8_icmp_f64(double %a, double %b0, double %b1, double %b2, doub
; AVX1: # %bb.0:
; AVX1-NEXT: cmpl %esi, %edi
; AVX1-NEXT: setl %al
-; AVX1-NEXT: vcmpltsd %xmm2, %xmm0, %xmm2
+; AVX1-NEXT: vcmpltsd %xmm4, %xmm0, %xmm4
+; AVX1-NEXT: vcmpltsd %xmm3, %xmm0, %xmm3
+; AVX1-NEXT: vandpd %xmm4, %xmm3, %xmm3
; AVX1-NEXT: vcmpltsd %xmm1, %xmm0, %xmm1
+; AVX1-NEXT: vcmpltsd %xmm2, %xmm0, %xmm2
; AVX1-NEXT: vandpd %xmm2, %xmm1, %xmm1
-; AVX1-NEXT: vmovd %xmm1, %ecx
-; AVX1-NEXT: vcmpltsd %xmm4, %xmm0, %xmm1
-; AVX1-NEXT: vcmpltsd %xmm3, %xmm0, %xmm2
-; AVX1-NEXT: vandpd %xmm1, %xmm2, %xmm1
-; AVX1-NEXT: vmovd %xmm1, %edx
-; AVX1-NEXT: andl %ecx, %edx
-; AVX1-NEXT: vcmpltsd %xmm6, %xmm0, %xmm1
-; AVX1-NEXT: vcmpltsd %xmm5, %xmm0, %xmm2
-; AVX1-NEXT: vandpd %xmm1, %xmm2, %xmm1
+; AVX1-NEXT: vandpd %xmm1, %xmm3, %xmm1
; AVX1-NEXT: vmovd %xmm1, %ecx
; AVX1-NEXT: andb %al, %cl
-; AVX1-NEXT: andb %dl, %cl
; AVX1-NEXT: vcmpltsd %xmm7, %xmm0, %xmm1
-; AVX1-NEXT: vcmpltsd {{[0-9]+}}(%rsp), %xmm0, %xmm0
+; AVX1-NEXT: vcmpltsd {{[0-9]+}}(%rsp), %xmm0, %xmm2
+; AVX1-NEXT: vcmpltsd %xmm6, %xmm0, %xmm3
+; AVX1-NEXT: vandpd %xmm3, %xmm1, %xmm1
+; AVX1-NEXT: vcmpltsd %xmm5, %xmm0, %xmm0
; AVX1-NEXT: vandpd %xmm0, %xmm1, %xmm0
+; AVX1-NEXT: vandpd %xmm2, %xmm0, %xmm0
; AVX1-NEXT: vmovd %xmm0, %eax
; AVX1-NEXT: andb %cl, %al
; AVX1-NEXT: # kill: def $al killed $al killed $eax
@@ -1337,23 +1296,21 @@ define i1 @olt_and8_icmp_f64(double %a, double %b0, double %b1, double %b2, doub
; AVX512: # %bb.0:
; AVX512-NEXT: cmpl %esi, %edi
; AVX512-NEXT: setl %al
-; AVX512-NEXT: vcmpltsd %xmm2, %xmm0, %k0
-; AVX512-NEXT: vcmpltsd %xmm1, %xmm0, %k1
-; AVX512-NEXT: kandw %k0, %k1, %k0
-; AVX512-NEXT: kmovw %k0, %ecx
; AVX512-NEXT: vcmpltsd %xmm4, %xmm0, %k0
; AVX512-NEXT: vcmpltsd %xmm3, %xmm0, %k1
; AVX512-NEXT: kandw %k0, %k1, %k0
-; AVX512-NEXT: kmovw %k0, %edx
-; AVX512-NEXT: andb %cl, %dl
-; AVX512-NEXT: vcmpltsd %xmm6, %xmm0, %k0
-; AVX512-NEXT: vcmpltsd %xmm5, %xmm0, %k1
-; AVX512-NEXT: kandw %k0, %k1, %k0
+; AVX512-NEXT: vcmpltsd %xmm1, %xmm0, %k1
+; AVX512-NEXT: kandw %k1, %k0, %k0
+; AVX512-NEXT: vcmpltsd %xmm2, %xmm0, %k1
+; AVX512-NEXT: kandw %k1, %k0, %k0
; AVX512-NEXT: kmovw %k0, %ecx
; AVX512-NEXT: andb %al, %cl
-; AVX512-NEXT: andb %dl, %cl
-; AVX512-NEXT: vcmpltsd %xmm7, %xmm0, %k0
-; AVX512-NEXT: vcmpltsd {{[0-9]+}}(%rsp), %xmm0, %k1
+; AVX512-NEXT: vcmpltsd %xmm6, %xmm0, %k0
+; AVX512-NEXT: vcmpltsd %xmm7, %xmm0, %k1
+; AVX512-NEXT: vcmpltsd {{[0-9]+}}(%rsp), %xmm0, %k2
+; AVX512-NEXT: kandw %k2, %k1, %k1
+; AVX512-NEXT: kandw %k0, %k1, %k0
+; AVX512-NEXT: vcmpltsd %xmm5, %xmm0, %k1
; AVX512-NEXT: kandw %k1, %k0, %k0
; AVX512-NEXT: kmovw %k0, %eax
; AVX512-NEXT: andb %cl, %al
>From 4991ad974d1c76db578659fe17fd29200f04e612 Mon Sep 17 00:00:00 2001
From: Tim Besard <tim.besard at gmail.com>
Date: Mon, 28 Sep 2026 15:46:17 +0200
Subject: [PATCH 6/6] [X86] Clean up the FP compare to FP logic conversion
Classify each operand of i1 logic once: a single-use scalar FP compare
that can be done as a vector compare, or element 0 of FP compares that
were already converted, both mapping to the vXi1 type they can be
computed in. Converting a pair of such operands then covers pairs of
compares, adding a compare to converted logic and merging two converted
sequences, and the nested logic look-through only retries it with an
operand of the inner op. The bitcast FP logic path is back to its
original form, and the extract uses getExtractVectorElt.
Only the operand order of some vector/mask logic changes in the tests.
---
llvm/lib/Target/X86/X86ISelLowering.cpp | 206 ++++++++++-------------
llvm/test/CodeGen/X86/fcmp-logic-fp16.ll | 4 +-
llvm/test/CodeGen/X86/fcmp-logic.ll | 86 +++++-----
3 files changed, 138 insertions(+), 158 deletions(-)
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 73ed56c14a1ef..4286db4cc8fbd 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -52659,27 +52659,59 @@ static unsigned convertIntLogicToFPLogicOpcode(unsigned Opcode) {
}
/// Return true if \p V is a tree of single-use vector logic ops over vector
-/// compares of scalar FP values, as created by convertIntLogicToFPLogic. Limit
-/// the depth so that, after one more logic op is added,
-/// SimplifyDemandedVectorElts on the final extract still reaches every compare:
-/// otherwise the X86ISD::CMPM mask compares are not scalarized and are widened
-/// to 512 bits without AVX512VL.
-static bool isConvertedFPLogic(SDValue V, unsigned Depth = 0) {
+/// compares of scalar FP values, like the ones convertIntLogicToFPLogic
+/// creates. \p V becomes an operand of new vector logic, from whose extract of
+/// element 0 SimplifyDemandedVectorElts should still reach every compare within
+/// the recursion limit: otherwise the X86ISD::CMPM mask compares are not
+/// scalarized and are widened to 512 bits without AVX512VL.
+static bool isConvertedFPLogic(SDValue V, unsigned Depth) {
+ if (Depth >= SelectionDAG::MaxRecursionDepth)
+ return false;
if (V.getOpcode() == ISD::SETCC)
return V.getOperand(0).getOpcode() == ISD::SCALAR_TO_VECTOR &&
V.getOperand(0).getValueType().isFloatingPoint();
- if (Depth >= SelectionDAG::MaxRecursionDepth - 2 ||
- !ISD::isBitwiseLogicOp(V.getOpcode()) || !V.hasOneUse())
+ if (!ISD::isBitwiseLogicOp(V.getOpcode()) || !V.hasOneUse())
return false;
return isConvertedFPLogic(V.getOperand(0), Depth + 1) &&
isConvertedFPLogic(V.getOperand(1), Depth + 1);
}
+/// If the single-use i1 value \p Op is a scalar FP compare that can be done as
+/// a vector compare, or element 0 of FP compares that were already converted to
+/// vector logic, return the vXi1 type it can be computed in. Otherwise return
+/// an invalid type.
+static MVT getFPLogicBoolVecVT(SDValue Op, const X86Subtarget &Subtarget) {
+ using namespace SDPatternMatch;
+ SDValue Vec, LHS;
+ ISD::CondCode CC;
+ if (!Op.hasOneUse())
+ return MVT();
+ if (sd_match(Op, m_ExtractElt(m_Value(Vec), m_Zero())))
+ return isConvertedFPLogic(Vec, /*Depth=*/1) ? Vec.getSimpleValueType()
+ : MVT();
+ if (!sd_match(Op, m_SetCC(m_Value(LHS), m_Value(), m_CondCode(CC))))
+ return MVT();
+
+ // v8f16 compares are only legal with AVX512VL.
+ EVT FPVT = LHS.getValueType();
+ if (!((Subtarget.hasSSE1() && FPVT == MVT::f32) ||
+ (Subtarget.hasSSE2() && FPVT == MVT::f64) ||
+ (Subtarget.hasFP16() && Subtarget.hasVLX() && FPVT == MVT::f16)))
+ return MVT();
+
+ // The vector ISA for FP predicates is incomplete before AVX, so converting
+ // COMIS* to CMPS* may not be a win before AVX.
+ if (!Subtarget.hasAVX() && !cheapX86FSETCC_SSE(CC))
+ return MVT();
+
+ return MVT::getVectorVT(MVT::i1, 128 / FPVT.getSizeInBits());
+}
+
/// If both input operands of a logic op are being cast from floating-point
/// types or FP compares, try to convert this into a floating-point logic node
-/// to avoid unnecessary moves from SSE to integer registers. For i1 logic, also
-/// add FP compares to ones that were already converted, and look through one
-/// level of a nested logic op of the same kind to pair up two FP compares.
+/// to avoid unnecessary moves from SSE to integer registers. FP compares that
+/// were already converted can be extended, and for a nested logic op of the
+/// same kind, one of its FP compares can be paired with the other operand.
static SDValue convertIntLogicToFPLogic(unsigned Opc, const SDLoc &DL, EVT VT,
SDValue N0, SDValue N1,
SelectionDAG &DAG,
@@ -52689,74 +52721,54 @@ static SDValue convertIntLogicToFPLogic(unsigned Opc, const SDLoc &DL, EVT VT,
"Unexpected bit opcode");
using namespace SDPatternMatch;
- auto IsLegalFPType = [&](EVT FPVT) {
- return (Subtarget.hasSSE1() && FPVT == MVT::f32) ||
- (Subtarget.hasSSE2() && FPVT == MVT::f64) ||
- (Subtarget.hasFP16() && FPVT == MVT::f16);
- };
- // Without AVX512VL, the v8f16 compares are not legal.
- auto IsLegalFPCmpType = [&](EVT FPVT) {
- return IsLegalFPType(FPVT) && (FPVT != MVT::f16 || Subtarget.hasVLX());
- };
+ if (VT == MVT::i1) {
+ // Convert scalar FP compares and logic to vector compares (COMIS* to
+ // CMPS*) and vector logic, or add to vector logic that was already
+ // converted:
+ // logic (setcc N00, N01), (setcc N10, N11) -->
+ // extelt (logic (setcc (s2v N00), (s2v N01)),
+ // (setcc (s2v N10), (s2v N11))), 0
+ // logic (extelt V, 0), (setcc N10, N11) -->
+ // extelt (logic V, (setcc (s2v N10), (s2v N11))), 0
+ auto GetBoolVec = [&](SDValue Op, MVT BoolVecVT) {
+ if (Op.getOpcode() == ISD::EXTRACT_VECTOR_ELT)
+ return Op.getOperand(0);
+ SDValue LHS = Op.getOperand(0);
+ SDValue RHS = Op.getOperand(1);
+ MVT VecVT = BoolVecVT.changeVectorElementType(LHS.getSimpleValueType());
+ return DAG.getSetCC(DL, BoolVecVT,
+ DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, VecVT, LHS),
+ DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, VecVT, RHS),
+ cast<CondCodeSDNode>(Op.getOperand(2))->get());
+ };
+ auto ConvertPair = [&](SDValue A, SDValue B) {
+ MVT BoolVecVT = getFPLogicBoolVecVT(A, Subtarget);
+ if (!BoolVecVT.isVector() ||
+ BoolVecVT != getFPLogicBoolVecVT(B, Subtarget))
+ return SDValue();
+ SDValue Logic = DAG.getNode(Opc, DL, BoolVecVT, GetBoolVec(A, BoolVecVT),
+ GetBoolVec(B, BoolVecVT));
+ return DAG.getExtractVectorElt(DL, VT, Logic, 0);
+ };
+ if (SDValue FPLogic = ConvertPair(N0, N1))
+ return FPLogic;
- // Look through a single-use inner logic op to pair up two FP compares that
- // it separates, e.g. by an integer compare. The recursive call only sees
- // SETCC or converted operands, so this is limited to one level:
- // logic (logic (setcc X), Y), (setcc Z) -->
- // logic (logic (setcc X), (setcc Z)), Y
- auto FPCmp = [](SDValue &Cmp) {
- return m_Value(
- Cmp,
- m_AnyOf(m_SetCC(m_FloatingPointVT(), m_Value(), m_Value()),
- m_ExtractElt(m_BitwiseLogic(m_Value(), m_Value()), m_Zero())));
- };
- SDValue X, Y, Z;
- auto Inner = m_OneUse(m_c_BinOp(Opc, FPCmp(X), m_Value(Y)));
- if (VT == MVT::i1 && ((sd_match(N0, Inner) && sd_match(N1, FPCmp(Z))) ||
- (sd_match(N1, Inner) && sd_match(N0, FPCmp(Z)))))
- if (SDValue FPLogic =
- convertIntLogicToFPLogic(Opc, DL, VT, X, Z, DAG, DCI, Subtarget))
- return DAG.getNode(Opc, DL, VT, FPLogic, Y);
-
- // Add an FP compare, or another converted sequence, to FP compares that
- // were already converted to vector logic (see below):
- // logic (extelt V, 0), (setcc LHS, RHS) -->
- // extelt (logic V, (setcc (s2v LHS), (s2v RHS))), 0
- // logic (extelt V, 0), (extelt W, 0) --> extelt (logic V, W), 0
- auto IsConverted = [](SDValue Op, SDValue &Vec) {
- return sd_match(Op, m_OneUse(m_ExtractElt(m_Value(Vec), m_Zero()))) &&
- isConvertedFPLogic(Vec);
- };
- SDValue V, W, LHS, RHS;
- ISD::CondCode CC;
- if (VT == MVT::i1 && IsConverted(N1, V))
- std::swap(N0, N1);
- if (VT == MVT::i1 && IsConverted(N0, V)) {
- EVT BoolVecVT = V.getValueType();
- SDValue Vec1;
- if (IsConverted(N1, W)) {
- Vec1 = W;
- } else if (sd_match(N1, m_OneUse(m_SetCC(m_Value(LHS), m_Value(RHS),
- m_CondCode(CC)))) &&
- IsLegalFPCmpType(LHS.getValueType()) &&
- (Subtarget.hasAVX() || cheapX86FSETCC_SSE(CC))) {
- EVT VecVT = EVT::getVectorVT(*DAG.getContext(), LHS.getValueType(),
- BoolVecVT.getVectorNumElements());
- if (VecVT.getSizeInBits() == 128) {
- SDValue VecL = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, VecVT, LHS);
- SDValue VecR = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, VecVT, RHS);
- Vec1 = DAG.getSetCC(DL, BoolVecVT, VecL, VecR, CC);
- }
- }
- if (Vec1 && Vec1.getValueType() == BoolVecVT) {
- SDValue Logic = DAG.getNode(Opc, DL, BoolVecVT, V, Vec1);
- return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, VT, Logic,
- DAG.getVectorIdxConstant(0, DL));
+ // Look through one level of a single-use inner logic op to pair up FP
+ // compares that it separates, e.g. by an integer compare:
+ // logic (logic X, Y), Z --> logic (logic X, Z), Y
+ SDValue X, Y;
+ for (auto [Inner, Z] : {std::pair(N0, N1), std::pair(N1, N0)}) {
+ if (!sd_match(Inner, m_OneUse(m_BinOp(Opc, m_Value(X), m_Value(Y)))))
+ continue;
+ if (SDValue FPLogic = ConvertPair(X, Z))
+ return DAG.getNode(Opc, DL, VT, FPLogic, Y);
+ if (SDValue FPLogic = ConvertPair(Y, Z))
+ return DAG.getNode(Opc, DL, VT, FPLogic, X);
}
}
- if (!((N0.getOpcode() == ISD::BITCAST && N1.getOpcode() == ISD::BITCAST) ||
- (N0.getOpcode() == ISD::SETCC && N1.getOpcode() == ISD::SETCC)))
+ if (N0.getOpcode() != ISD::BITCAST || N1.getOpcode() != ISD::BITCAST ||
+ DCI.isBeforeLegalizeOps())
return SDValue();
SDValue N00 = N0.getOperand(0);
@@ -52765,46 +52777,14 @@ static SDValue convertIntLogicToFPLogic(unsigned Opc, const SDLoc &DL, EVT VT,
EVT N10Type = N10.getValueType();
// Ensure that both types are the same and are legal scalar fp types.
- if (N00Type != N10Type || !IsLegalFPType(N00Type))
+ if (N00Type != N10Type || !((Subtarget.hasSSE1() && N00Type == MVT::f32) ||
+ (Subtarget.hasSSE2() && N00Type == MVT::f64) ||
+ (Subtarget.hasFP16() && N00Type == MVT::f16)))
return SDValue();
- if (N0.getOpcode() == ISD::BITCAST && !DCI.isBeforeLegalizeOps()) {
- unsigned FPOpcode = convertIntLogicToFPLogicOpcode(Opc);
- SDValue FPLogic = DAG.getNode(FPOpcode, DL, N00Type, N00, N10);
- return DAG.getBitcast(VT, FPLogic);
- }
-
- if (VT != MVT::i1 || N0.getOpcode() != ISD::SETCC || !N0.hasOneUse() ||
- !N1.hasOneUse() || !IsLegalFPCmpType(N00Type))
- return SDValue();
-
- ISD::CondCode CC0 = cast<CondCodeSDNode>(N0.getOperand(2))->get();
- ISD::CondCode CC1 = cast<CondCodeSDNode>(N1.getOperand(2))->get();
-
- // The vector ISA for FP predicates is incomplete before AVX, so converting
- // COMIS* to CMPS* may not be a win before AVX.
- if (!Subtarget.hasAVX() &&
- !(cheapX86FSETCC_SSE(CC0) && cheapX86FSETCC_SSE(CC1)))
- return SDValue();
-
- // Convert scalar FP compares and logic to vector compares (COMIS* to CMPS*)
- // and vector logic:
- // logic (setcc N00, N01), (setcc N10, N11) -->
- // extelt (logic (setcc (s2v N00), (s2v N01)), setcc (s2v N10), (s2v N11))), 0
- unsigned NumElts = 128 / N00Type.getSizeInBits();
- EVT VecVT = EVT::getVectorVT(*DAG.getContext(), N00Type, NumElts);
- EVT BoolVecVT = EVT::getVectorVT(*DAG.getContext(), MVT::i1, NumElts);
- SDValue ZeroIndex = DAG.getVectorIdxConstant(0, DL);
- SDValue N01 = N0.getOperand(1);
- SDValue N11 = N1.getOperand(1);
- SDValue Vec00 = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, VecVT, N00);
- SDValue Vec01 = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, VecVT, N01);
- SDValue Vec10 = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, VecVT, N10);
- SDValue Vec11 = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, VecVT, N11);
- SDValue Setcc0 = DAG.getSetCC(DL, BoolVecVT, Vec00, Vec01, CC0);
- SDValue Setcc1 = DAG.getSetCC(DL, BoolVecVT, Vec10, Vec11, CC1);
- SDValue Logic = DAG.getNode(Opc, DL, BoolVecVT, Setcc0, Setcc1);
- return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, VT, Logic, ZeroIndex);
+ unsigned FPOpcode = convertIntLogicToFPLogicOpcode(Opc);
+ SDValue FPLogic = DAG.getNode(FPOpcode, DL, N00Type, N00, N10);
+ return DAG.getBitcast(VT, FPLogic);
}
// Attempt to fold BITOP(MOVMSK(X),MOVMSK(Y)) -> MOVMSK(BITOP(X,Y))
diff --git a/llvm/test/CodeGen/X86/fcmp-logic-fp16.ll b/llvm/test/CodeGen/X86/fcmp-logic-fp16.ll
index caed749ec8894..c3c33b097f754 100644
--- a/llvm/test/CodeGen/X86/fcmp-logic-fp16.ll
+++ b/llvm/test/CodeGen/X86/fcmp-logic-fp16.ll
@@ -55,9 +55,9 @@ define i1 @mixed_and5_f16(half %a, half %b, half %c, half %d, half %e, half %f)
; VL-NEXT: vcmpneqsh %xmm4, %xmm0, %k1
; VL-NEXT: kandw %k0, %k1, %k0
; VL-NEXT: vcmpeqsh %xmm3, %xmm0, %k1
-; VL-NEXT: kandw %k1, %k0, %k0
+; VL-NEXT: kandw %k0, %k1, %k0
; VL-NEXT: vcmpltsh %xmm0, %xmm1, %k1
-; VL-NEXT: kandw %k1, %k0, %k0
+; VL-NEXT: kandw %k0, %k1, %k0
; VL-NEXT: vcmpltsh %xmm2, %xmm0, %k1
; VL-NEXT: kandw %k1, %k0, %k0
; VL-NEXT: kmovd %k0, %eax
diff --git a/llvm/test/CodeGen/X86/fcmp-logic.ll b/llvm/test/CodeGen/X86/fcmp-logic.ll
index 656bf8d53a5a2..36329a08bf203 100644
--- a/llvm/test/CodeGen/X86/fcmp-logic.ll
+++ b/llvm/test/CodeGen/X86/fcmp-logic.ll
@@ -695,8 +695,8 @@ define i1 @ogt_and5_f32(float %a, float %b, float %c, float %d, float %e, float
; AVX1-NEXT: vandps %xmm5, %xmm4, %xmm4
; AVX1-NEXT: vcmpltss %xmm0, %xmm3, %xmm3
; AVX1-NEXT: vcmpltss %xmm0, %xmm1, %xmm1
-; AVX1-NEXT: vandps %xmm1, %xmm3, %xmm1
-; AVX1-NEXT: vandps %xmm1, %xmm4, %xmm1
+; AVX1-NEXT: vandps %xmm3, %xmm1, %xmm1
+; AVX1-NEXT: vandps %xmm4, %xmm1, %xmm1
; AVX1-NEXT: vcmpltss %xmm0, %xmm2, %xmm0
; AVX1-NEXT: vandps %xmm0, %xmm1, %xmm0
; AVX1-NEXT: vmovd %xmm0, %eax
@@ -709,9 +709,9 @@ define i1 @ogt_and5_f32(float %a, float %b, float %c, float %d, float %e, float
; AVX512-NEXT: vcmpltss %xmm0, %xmm4, %k1
; AVX512-NEXT: kandw %k0, %k1, %k0
; AVX512-NEXT: vcmpltss %xmm0, %xmm3, %k1
-; AVX512-NEXT: kandw %k1, %k0, %k0
+; AVX512-NEXT: kandw %k0, %k1, %k0
; AVX512-NEXT: vcmpltss %xmm0, %xmm1, %k1
-; AVX512-NEXT: kandw %k1, %k0, %k0
+; AVX512-NEXT: kandw %k0, %k1, %k0
; AVX512-NEXT: vcmpltss %xmm0, %xmm2, %k1
; AVX512-NEXT: kandw %k1, %k0, %k0
; AVX512-NEXT: kmovw %k0, %eax
@@ -752,8 +752,8 @@ define i1 @mixed_and5_f32(float %a, float %b, float %c, float %d, float %e, floa
; AVX1-NEXT: vandps %xmm5, %xmm4, %xmm4
; AVX1-NEXT: vcmpeqss %xmm3, %xmm0, %xmm3
; AVX1-NEXT: vcmpltss %xmm0, %xmm1, %xmm1
-; AVX1-NEXT: vandps %xmm1, %xmm3, %xmm1
-; AVX1-NEXT: vandps %xmm1, %xmm4, %xmm1
+; AVX1-NEXT: vandps %xmm3, %xmm1, %xmm1
+; AVX1-NEXT: vandps %xmm4, %xmm1, %xmm1
; AVX1-NEXT: vcmpltss %xmm2, %xmm0, %xmm0
; AVX1-NEXT: vandps %xmm0, %xmm1, %xmm0
; AVX1-NEXT: vmovd %xmm0, %eax
@@ -766,9 +766,9 @@ define i1 @mixed_and5_f32(float %a, float %b, float %c, float %d, float %e, floa
; AVX512-NEXT: vcmpneqss %xmm4, %xmm0, %k1
; AVX512-NEXT: kandw %k0, %k1, %k0
; AVX512-NEXT: vcmpeqss %xmm3, %xmm0, %k1
-; AVX512-NEXT: kandw %k1, %k0, %k0
+; AVX512-NEXT: kandw %k0, %k1, %k0
; AVX512-NEXT: vcmpltss %xmm0, %xmm1, %k1
-; AVX512-NEXT: kandw %k1, %k0, %k0
+; AVX512-NEXT: kandw %k0, %k1, %k0
; AVX512-NEXT: vcmpltss %xmm2, %xmm0, %k1
; AVX512-NEXT: kandw %k1, %k0, %k0
; AVX512-NEXT: kmovw %k0, %eax
@@ -809,8 +809,8 @@ define i1 @mixed_or5_f64(double %a, double %b, double %c, double %d, double %e,
; AVX1-NEXT: vorpd %xmm5, %xmm4, %xmm4
; AVX1-NEXT: vcmpeqsd %xmm3, %xmm0, %xmm3
; AVX1-NEXT: vcmpltsd %xmm0, %xmm1, %xmm1
-; AVX1-NEXT: vorpd %xmm1, %xmm3, %xmm1
-; AVX1-NEXT: vorpd %xmm1, %xmm4, %xmm1
+; AVX1-NEXT: vorpd %xmm3, %xmm1, %xmm1
+; AVX1-NEXT: vorpd %xmm4, %xmm1, %xmm1
; AVX1-NEXT: vcmpltsd %xmm2, %xmm0, %xmm0
; AVX1-NEXT: vorpd %xmm0, %xmm1, %xmm0
; AVX1-NEXT: vmovd %xmm0, %eax
@@ -823,9 +823,9 @@ define i1 @mixed_or5_f64(double %a, double %b, double %c, double %d, double %e,
; AVX512-NEXT: vcmpneqsd %xmm4, %xmm0, %k1
; AVX512-NEXT: korw %k0, %k1, %k0
; AVX512-NEXT: vcmpeqsd %xmm3, %xmm0, %k1
-; AVX512-NEXT: korw %k1, %k0, %k0
+; AVX512-NEXT: korw %k0, %k1, %k0
; AVX512-NEXT: vcmpltsd %xmm0, %xmm1, %k1
-; AVX512-NEXT: korw %k1, %k0, %k0
+; AVX512-NEXT: korw %k0, %k1, %k0
; AVX512-NEXT: vcmpltsd %xmm2, %xmm0, %k1
; AVX512-NEXT: korw %k1, %k0, %k0
; AVX512-NEXT: kmovw %k0, %eax
@@ -867,7 +867,7 @@ define i1 @olt_icmp_ole_oge_and_f64(double %w, double %x, double %y, double %z,
; AVX1-NEXT: vcmplesd %xmm3, %xmm2, %xmm2
; AVX1-NEXT: vandpd %xmm4, %xmm2, %xmm2
; AVX1-NEXT: vcmpltsd %xmm1, %xmm0, %xmm0
-; AVX1-NEXT: vandpd %xmm0, %xmm2, %xmm0
+; AVX1-NEXT: vandpd %xmm2, %xmm0, %xmm0
; AVX1-NEXT: vmovd %xmm0, %eax
; AVX1-NEXT: andb %cl, %al
; AVX1-NEXT: # kill: def $al killed $al killed $eax
@@ -881,7 +881,7 @@ define i1 @olt_icmp_ole_oge_and_f64(double %w, double %x, double %y, double %z,
; AVX512-NEXT: vcmplesd %xmm3, %xmm2, %k1
; AVX512-NEXT: kandw %k0, %k1, %k0
; AVX512-NEXT: vcmpltsd %xmm1, %xmm0, %k1
-; AVX512-NEXT: kandw %k1, %k0, %k0
+; AVX512-NEXT: kandw %k0, %k1, %k0
; AVX512-NEXT: kmovw %k0, %eax
; AVX512-NEXT: andb %cl, %al
; AVX512-NEXT: # kill: def $al killed $al killed $eax
@@ -968,8 +968,8 @@ define i1 @mixed_xor5_f32(float %a, float %b, float %c, float %d, float %e, floa
; AVX1-NEXT: vxorps %xmm5, %xmm4, %xmm4
; AVX1-NEXT: vcmpeqss %xmm3, %xmm0, %xmm3
; AVX1-NEXT: vcmpltss %xmm0, %xmm1, %xmm1
-; AVX1-NEXT: vxorps %xmm1, %xmm3, %xmm1
-; AVX1-NEXT: vxorps %xmm1, %xmm4, %xmm1
+; AVX1-NEXT: vxorps %xmm3, %xmm1, %xmm1
+; AVX1-NEXT: vxorps %xmm4, %xmm1, %xmm1
; AVX1-NEXT: vcmpltss %xmm2, %xmm0, %xmm0
; AVX1-NEXT: vxorps %xmm0, %xmm1, %xmm0
; AVX1-NEXT: vmovd %xmm0, %eax
@@ -982,9 +982,9 @@ define i1 @mixed_xor5_f32(float %a, float %b, float %c, float %d, float %e, floa
; AVX512-NEXT: vcmpneqss %xmm4, %xmm0, %k1
; AVX512-NEXT: kxorw %k0, %k1, %k0
; AVX512-NEXT: vcmpeqss %xmm3, %xmm0, %k1
-; AVX512-NEXT: kxorw %k1, %k0, %k0
+; AVX512-NEXT: kxorw %k0, %k1, %k0
; AVX512-NEXT: vcmpltss %xmm0, %xmm1, %k1
-; AVX512-NEXT: kxorw %k1, %k0, %k0
+; AVX512-NEXT: kxorw %k0, %k1, %k0
; AVX512-NEXT: vcmpltss %xmm2, %xmm0, %k1
; AVX512-NEXT: kxorw %k1, %k0, %k0
; AVX512-NEXT: kmovw %k0, %eax
@@ -1049,7 +1049,7 @@ define i1 @olt_and10_f64(double %a, double %b0, double %b1, double %b2, double %
; AVX1-NEXT: vcmpltsd %xmm1, %xmm0, %xmm1
; AVX1-NEXT: vcmpltsd %xmm2, %xmm0, %xmm2
; AVX1-NEXT: vandpd %xmm2, %xmm1, %xmm1
-; AVX1-NEXT: vandpd %xmm1, %xmm3, %xmm1
+; AVX1-NEXT: vandpd %xmm3, %xmm1, %xmm1
; AVX1-NEXT: vmovd %xmm1, %ecx
; AVX1-NEXT: vmovsd {{.*#+}} xmm1 = mem[0],zero
; AVX1-NEXT: vcmpltpd %xmm1, %xmm0, %xmm1
@@ -1059,12 +1059,12 @@ define i1 @olt_and10_f64(double %a, double %b0, double %b1, double %b2, double %
; AVX1-NEXT: vmovsd {{.*#+}} xmm2 = mem[0],zero
; AVX1-NEXT: vcmpltpd %xmm2, %xmm0, %xmm2
; AVX1-NEXT: vcmpltsd %xmm7, %xmm0, %xmm3
-; AVX1-NEXT: vandpd %xmm3, %xmm2, %xmm2
-; AVX1-NEXT: vandpd %xmm2, %xmm1, %xmm1
+; AVX1-NEXT: vandpd %xmm2, %xmm3, %xmm2
+; AVX1-NEXT: vandpd %xmm1, %xmm2, %xmm1
; AVX1-NEXT: vcmpltsd %xmm6, %xmm0, %xmm2
; AVX1-NEXT: vcmpltsd %xmm5, %xmm0, %xmm0
-; AVX1-NEXT: vandpd %xmm0, %xmm2, %xmm0
-; AVX1-NEXT: vandpd %xmm0, %xmm1, %xmm0
+; AVX1-NEXT: vandpd %xmm2, %xmm0, %xmm0
+; AVX1-NEXT: vandpd %xmm1, %xmm0, %xmm0
; AVX1-NEXT: vmovd %xmm0, %eax
; AVX1-NEXT: andl %ecx, %eax
; AVX1-NEXT: # kill: def $al killed $al killed $eax
@@ -1076,7 +1076,7 @@ define i1 @olt_and10_f64(double %a, double %b0, double %b1, double %b2, double %
; AVX512-NEXT: vcmpltsd %xmm3, %xmm0, %k1
; AVX512-NEXT: kandw %k0, %k1, %k0
; AVX512-NEXT: vcmpltsd %xmm1, %xmm0, %k1
-; AVX512-NEXT: kandw %k1, %k0, %k0
+; AVX512-NEXT: kandw %k0, %k1, %k0
; AVX512-NEXT: vcmpltsd %xmm2, %xmm0, %k1
; AVX512-NEXT: kandw %k1, %k0, %k0
; AVX512-NEXT: kmovw %k0, %ecx
@@ -1085,12 +1085,12 @@ define i1 @olt_and10_f64(double %a, double %b0, double %b1, double %b2, double %
; AVX512-NEXT: vcmpltsd {{[0-9]+}}(%rsp), %xmm0, %k2
; AVX512-NEXT: kandw %k1, %k2, %k1
; AVX512-NEXT: vcmpltsd {{[0-9]+}}(%rsp), %xmm0, %k2
-; AVX512-NEXT: kandw %k2, %k1, %k1
-; AVX512-NEXT: kandw %k0, %k1, %k0
-; AVX512-NEXT: vcmpltsd %xmm6, %xmm0, %k1
+; AVX512-NEXT: kandw %k1, %k2, %k1
; AVX512-NEXT: kandw %k1, %k0, %k0
+; AVX512-NEXT: vcmpltsd %xmm6, %xmm0, %k1
+; AVX512-NEXT: kandw %k0, %k1, %k0
; AVX512-NEXT: vcmpltsd %xmm5, %xmm0, %k1
-; AVX512-NEXT: kandw %k1, %k0, %k0
+; AVX512-NEXT: kandw %k0, %k1, %k0
; AVX512-NEXT: kmovw %k0, %eax
; AVX512-NEXT: andb %cl, %al
; AVX512-NEXT: # kill: def $al killed $al killed $eax
@@ -1165,7 +1165,7 @@ define i1 @olt_and5_and5_f64(double %a, double %b0, double %b1, double %b2, doub
; AVX1-NEXT: vcmpltsd %xmm1, %xmm0, %xmm1
; AVX1-NEXT: vcmpltsd %xmm2, %xmm0, %xmm2
; AVX1-NEXT: vandpd %xmm2, %xmm1, %xmm1
-; AVX1-NEXT: vandpd %xmm1, %xmm3, %xmm1
+; AVX1-NEXT: vandpd %xmm3, %xmm1, %xmm1
; AVX1-NEXT: vmovsd {{.*#+}} xmm2 = mem[0],zero
; AVX1-NEXT: vcmpltpd %xmm2, %xmm0, %xmm2
; AVX1-NEXT: vmovsd {{.*#+}} xmm3 = mem[0],zero
@@ -1174,13 +1174,13 @@ define i1 @olt_and5_and5_f64(double %a, double %b0, double %b1, double %b2, doub
; AVX1-NEXT: vmovsd {{.*#+}} xmm3 = mem[0],zero
; AVX1-NEXT: vcmpltpd %xmm3, %xmm0, %xmm3
; AVX1-NEXT: vcmpltsd %xmm6, %xmm0, %xmm4
-; AVX1-NEXT: vandpd %xmm4, %xmm3, %xmm3
-; AVX1-NEXT: vandpd %xmm3, %xmm2, %xmm2
+; AVX1-NEXT: vandpd %xmm3, %xmm4, %xmm3
+; AVX1-NEXT: vandpd %xmm2, %xmm3, %xmm2
; AVX1-NEXT: vcmpltsd %xmm7, %xmm0, %xmm3
; AVX1-NEXT: vmovd %xmm1, %ecx
; AVX1-NEXT: vcmpltsd %xmm5, %xmm0, %xmm0
-; AVX1-NEXT: vandpd %xmm0, %xmm3, %xmm0
-; AVX1-NEXT: vandpd %xmm0, %xmm2, %xmm0
+; AVX1-NEXT: vandpd %xmm3, %xmm0, %xmm0
+; AVX1-NEXT: vandpd %xmm2, %xmm0, %xmm0
; AVX1-NEXT: vmovd %xmm0, %eax
; AVX1-NEXT: andl %ecx, %eax
; AVX1-NEXT: # kill: def $al killed $al killed $eax
@@ -1192,7 +1192,7 @@ define i1 @olt_and5_and5_f64(double %a, double %b0, double %b1, double %b2, doub
; AVX512-NEXT: vcmpltsd %xmm3, %xmm0, %k1
; AVX512-NEXT: kandw %k0, %k1, %k0
; AVX512-NEXT: vcmpltsd %xmm1, %xmm0, %k1
-; AVX512-NEXT: kandw %k1, %k0, %k0
+; AVX512-NEXT: kandw %k0, %k1, %k0
; AVX512-NEXT: vcmpltsd %xmm2, %xmm0, %k1
; AVX512-NEXT: kandw %k1, %k0, %k0
; AVX512-NEXT: kmovw %k0, %ecx
@@ -1201,12 +1201,12 @@ define i1 @olt_and5_and5_f64(double %a, double %b0, double %b1, double %b2, doub
; AVX512-NEXT: vcmpltsd {{[0-9]+}}(%rsp), %xmm0, %k2
; AVX512-NEXT: kandw %k1, %k2, %k1
; AVX512-NEXT: vcmpltsd {{[0-9]+}}(%rsp), %xmm0, %k2
-; AVX512-NEXT: kandw %k2, %k1, %k1
-; AVX512-NEXT: kandw %k0, %k1, %k0
+; AVX512-NEXT: kandw %k1, %k2, %k1
+; AVX512-NEXT: kandw %k1, %k0, %k0
; AVX512-NEXT: vcmpltsd %xmm7, %xmm0, %k1
; AVX512-NEXT: kandw %k1, %k0, %k0
; AVX512-NEXT: vcmpltsd %xmm5, %xmm0, %k1
-; AVX512-NEXT: kandw %k1, %k0, %k0
+; AVX512-NEXT: kandw %k0, %k1, %k0
; AVX512-NEXT: kmovw %k0, %eax
; AVX512-NEXT: andb %cl, %al
; AVX512-NEXT: # kill: def $al killed $al killed $eax
@@ -1277,15 +1277,15 @@ define i1 @olt_and8_icmp_f64(double %a, double %b0, double %b1, double %b2, doub
; AVX1-NEXT: vcmpltsd %xmm1, %xmm0, %xmm1
; AVX1-NEXT: vcmpltsd %xmm2, %xmm0, %xmm2
; AVX1-NEXT: vandpd %xmm2, %xmm1, %xmm1
-; AVX1-NEXT: vandpd %xmm1, %xmm3, %xmm1
+; AVX1-NEXT: vandpd %xmm3, %xmm1, %xmm1
; AVX1-NEXT: vmovd %xmm1, %ecx
; AVX1-NEXT: andb %al, %cl
; AVX1-NEXT: vcmpltsd %xmm7, %xmm0, %xmm1
; AVX1-NEXT: vcmpltsd {{[0-9]+}}(%rsp), %xmm0, %xmm2
; AVX1-NEXT: vcmpltsd %xmm6, %xmm0, %xmm3
-; AVX1-NEXT: vandpd %xmm3, %xmm1, %xmm1
+; AVX1-NEXT: vandpd %xmm1, %xmm3, %xmm1
; AVX1-NEXT: vcmpltsd %xmm5, %xmm0, %xmm0
-; AVX1-NEXT: vandpd %xmm0, %xmm1, %xmm0
+; AVX1-NEXT: vandpd %xmm1, %xmm0, %xmm0
; AVX1-NEXT: vandpd %xmm2, %xmm0, %xmm0
; AVX1-NEXT: vmovd %xmm0, %eax
; AVX1-NEXT: andb %cl, %al
@@ -1300,7 +1300,7 @@ define i1 @olt_and8_icmp_f64(double %a, double %b0, double %b1, double %b2, doub
; AVX512-NEXT: vcmpltsd %xmm3, %xmm0, %k1
; AVX512-NEXT: kandw %k0, %k1, %k0
; AVX512-NEXT: vcmpltsd %xmm1, %xmm0, %k1
-; AVX512-NEXT: kandw %k1, %k0, %k0
+; AVX512-NEXT: kandw %k0, %k1, %k0
; AVX512-NEXT: vcmpltsd %xmm2, %xmm0, %k1
; AVX512-NEXT: kandw %k1, %k0, %k0
; AVX512-NEXT: kmovw %k0, %ecx
@@ -1309,9 +1309,9 @@ define i1 @olt_and8_icmp_f64(double %a, double %b0, double %b1, double %b2, doub
; AVX512-NEXT: vcmpltsd %xmm7, %xmm0, %k1
; AVX512-NEXT: vcmpltsd {{[0-9]+}}(%rsp), %xmm0, %k2
; AVX512-NEXT: kandw %k2, %k1, %k1
-; AVX512-NEXT: kandw %k0, %k1, %k0
-; AVX512-NEXT: vcmpltsd %xmm5, %xmm0, %k1
; AVX512-NEXT: kandw %k1, %k0, %k0
+; AVX512-NEXT: vcmpltsd %xmm5, %xmm0, %k1
+; AVX512-NEXT: kandw %k0, %k1, %k0
; AVX512-NEXT: kmovw %k0, %eax
; AVX512-NEXT: andb %cl, %al
; AVX512-NEXT: # kill: def $al killed $al killed $eax
More information about the llvm-commits
mailing list