[llvm] [RISCV][GISel] Use a single FEQ for fcmp ord/uno x, x (PR #192022)
Jim Lin via llvm-commits
llvm-commits at lists.llvm.org
Tue Apr 14 01:24:27 PDT 2026
https://github.com/tclin914 created https://github.com/llvm/llvm-project/pull/192022
When both operands of an ORD/UNO compare are the same register,
the double-FEQ + AND sequence is redundant: a single FEQ x, x
gives the same result. Addresses the FIXME in selectFCmp.
>From 8bce6d4ad70d1aa2d805c0b38f22e8eb1bdf031f Mon Sep 17 00:00:00 2001
From: Jim Lin <jim at andestech.com>
Date: Tue, 14 Apr 2026 02:11:07 +0000
Subject: [PATCH 1/2] [RISCV][GISel] Add pre-commit tests for fcmp ord/uno x, x
Shows the currently-emitted redundant sequence (two FEQs plus AND)
when both operands of an ORD/UNO compare are the same register.
---
.../CodeGen/RISCV/GlobalISel/double-fcmp.ll | 73 +++++++++++++++++++
.../CodeGen/RISCV/GlobalISel/float-fcmp.ll | 71 ++++++++++++++++++
2 files changed, 144 insertions(+)
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/double-fcmp.ll b/llvm/test/CodeGen/RISCV/GlobalISel/double-fcmp.ll
index 9ec8c32e989b0..ac679cd434d94 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/double-fcmp.ll
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/double-fcmp.ll
@@ -587,3 +587,76 @@ define i32 @fcmp_true(double %a, double %b) nounwind {
%2 = zext i1 %1 to i32
ret i32 %2
}
+
+define i32 @fcmp_ord_same(double %a) nounwind {
+; CHECKIFD-LABEL: fcmp_ord_same:
+; CHECKIFD: # %bb.0:
+; CHECKIFD-NEXT: feq.d a0, fa0, fa0
+; CHECKIFD-NEXT: feq.d a1, fa0, fa0
+; CHECKIFD-NEXT: and a0, a0, a1
+; CHECKIFD-NEXT: ret
+;
+; RV32I-LABEL: fcmp_ord_same:
+; RV32I: # %bb.0:
+; RV32I-NEXT: addi sp, sp, -16
+; RV32I-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
+; RV32I-NEXT: mv a2, a0
+; RV32I-NEXT: mv a3, a1
+; RV32I-NEXT: call __unorddf2
+; RV32I-NEXT: seqz a0, a0
+; RV32I-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
+; RV32I-NEXT: addi sp, sp, 16
+; RV32I-NEXT: ret
+;
+; RV64I-LABEL: fcmp_ord_same:
+; RV64I: # %bb.0:
+; RV64I-NEXT: addi sp, sp, -16
+; RV64I-NEXT: sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-NEXT: mv a1, a0
+; RV64I-NEXT: call __unorddf2
+; RV64I-NEXT: sext.w a0, a0
+; RV64I-NEXT: seqz a0, a0
+; RV64I-NEXT: ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-NEXT: addi sp, sp, 16
+; RV64I-NEXT: ret
+ %1 = fcmp ord double %a, %a
+ %2 = zext i1 %1 to i32
+ ret i32 %2
+}
+
+define i32 @fcmp_uno_same(double %a) nounwind {
+; CHECKIFD-LABEL: fcmp_uno_same:
+; CHECKIFD: # %bb.0:
+; CHECKIFD-NEXT: feq.d a0, fa0, fa0
+; CHECKIFD-NEXT: feq.d a1, fa0, fa0
+; CHECKIFD-NEXT: and a0, a0, a1
+; CHECKIFD-NEXT: xori a0, a0, 1
+; CHECKIFD-NEXT: ret
+;
+; RV32I-LABEL: fcmp_uno_same:
+; RV32I: # %bb.0:
+; RV32I-NEXT: addi sp, sp, -16
+; RV32I-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
+; RV32I-NEXT: mv a2, a0
+; RV32I-NEXT: mv a3, a1
+; RV32I-NEXT: call __unorddf2
+; RV32I-NEXT: snez a0, a0
+; RV32I-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
+; RV32I-NEXT: addi sp, sp, 16
+; RV32I-NEXT: ret
+;
+; RV64I-LABEL: fcmp_uno_same:
+; RV64I: # %bb.0:
+; RV64I-NEXT: addi sp, sp, -16
+; RV64I-NEXT: sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-NEXT: mv a1, a0
+; RV64I-NEXT: call __unorddf2
+; RV64I-NEXT: sext.w a0, a0
+; RV64I-NEXT: snez a0, a0
+; RV64I-NEXT: ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-NEXT: addi sp, sp, 16
+; RV64I-NEXT: ret
+ %1 = fcmp uno double %a, %a
+ %2 = zext i1 %1 to i32
+ ret i32 %2
+}
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/float-fcmp.ll b/llvm/test/CodeGen/RISCV/GlobalISel/float-fcmp.ll
index 380751c907c0d..24e8b0148a39f 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/float-fcmp.ll
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/float-fcmp.ll
@@ -572,3 +572,74 @@ define i32 @fcmp_true(float %a, float %b) nounwind {
%2 = zext i1 %1 to i32
ret i32 %2
}
+
+define i32 @fcmp_ord_same(float %a) nounwind {
+; CHECKIF-LABEL: fcmp_ord_same:
+; CHECKIF: # %bb.0:
+; CHECKIF-NEXT: feq.s a0, fa0, fa0
+; CHECKIF-NEXT: feq.s a1, fa0, fa0
+; CHECKIF-NEXT: and a0, a0, a1
+; CHECKIF-NEXT: ret
+;
+; RV32I-LABEL: fcmp_ord_same:
+; RV32I: # %bb.0:
+; RV32I-NEXT: addi sp, sp, -16
+; RV32I-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
+; RV32I-NEXT: mv a1, a0
+; RV32I-NEXT: call __unordsf2
+; RV32I-NEXT: seqz a0, a0
+; RV32I-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
+; RV32I-NEXT: addi sp, sp, 16
+; RV32I-NEXT: ret
+;
+; RV64I-LABEL: fcmp_ord_same:
+; RV64I: # %bb.0:
+; RV64I-NEXT: addi sp, sp, -16
+; RV64I-NEXT: sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-NEXT: mv a1, a0
+; RV64I-NEXT: call __unordsf2
+; RV64I-NEXT: sext.w a0, a0
+; RV64I-NEXT: seqz a0, a0
+; RV64I-NEXT: ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-NEXT: addi sp, sp, 16
+; RV64I-NEXT: ret
+ %1 = fcmp ord float %a, %a
+ %2 = zext i1 %1 to i32
+ ret i32 %2
+}
+
+define i32 @fcmp_uno_same(float %a) nounwind {
+; CHECKIF-LABEL: fcmp_uno_same:
+; CHECKIF: # %bb.0:
+; CHECKIF-NEXT: feq.s a0, fa0, fa0
+; CHECKIF-NEXT: feq.s a1, fa0, fa0
+; CHECKIF-NEXT: and a0, a0, a1
+; CHECKIF-NEXT: xori a0, a0, 1
+; CHECKIF-NEXT: ret
+;
+; RV32I-LABEL: fcmp_uno_same:
+; RV32I: # %bb.0:
+; RV32I-NEXT: addi sp, sp, -16
+; RV32I-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
+; RV32I-NEXT: mv a1, a0
+; RV32I-NEXT: call __unordsf2
+; RV32I-NEXT: snez a0, a0
+; RV32I-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
+; RV32I-NEXT: addi sp, sp, 16
+; RV32I-NEXT: ret
+;
+; RV64I-LABEL: fcmp_uno_same:
+; RV64I: # %bb.0:
+; RV64I-NEXT: addi sp, sp, -16
+; RV64I-NEXT: sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-NEXT: mv a1, a0
+; RV64I-NEXT: call __unordsf2
+; RV64I-NEXT: sext.w a0, a0
+; RV64I-NEXT: snez a0, a0
+; RV64I-NEXT: ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-NEXT: addi sp, sp, 16
+; RV64I-NEXT: ret
+ %1 = fcmp uno float %a, %a
+ %2 = zext i1 %1 to i32
+ ret i32 %2
+}
>From bcac44d071e0351d9b72851bfd60f88a9e55c2ea Mon Sep 17 00:00:00 2001
From: Jim Lin <jim at andestech.com>
Date: Tue, 14 Apr 2026 02:12:26 +0000
Subject: [PATCH 2/2] [RISCV][GISel] Use a single FEQ for fcmp ord/uno x, x
When both operands of an ORD/UNO compare are the same register,
the double-FEQ + AND sequence is redundant: a single FEQ x, x
gives the same result. Addresses the FIXME in selectFCmp.
---
.../RISCV/GISel/RISCVInstructionSelector.cpp | 49 +++++++++++--------
.../CodeGen/RISCV/GlobalISel/double-fcmp.ll | 4 --
.../CodeGen/RISCV/GlobalISel/float-fcmp.ll | 4 --
3 files changed, 29 insertions(+), 28 deletions(-)
diff --git a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
index 60e65f9db3fc6..cf810d867d9ce 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
@@ -1922,29 +1922,38 @@ bool RISCVInstructionSelector::selectFPCompare(MachineInstr &MI) const {
constrainSelectedInstRegOperands(*Or, TII, TRI, RBI);
} else if (Pred == CmpInst::FCMP_ORD || Pred == CmpInst::FCMP_UNO) {
// fcmp ord LHS, RHS => (AND (FEQ LHS, LHS), (FEQ RHS, RHS))
- // FIXME: If LHS and RHS are the same we can use a single FEQ.
+ // If LHS and RHS are the same, a single FEQ suffices.
NeedInvert = Pred == CmpInst::FCMP_UNO;
- Register Cmp1Reg = MRI->createVirtualRegister(&RISCV::GPRRegClass);
- MachineInstr *Cmp1 =
- BuildMI(*MI.getParent(), MI, MI.getDebugLoc(),
- TII.get(getFCmpOpcode(CmpInst::FCMP_OEQ, Size)), Cmp1Reg)
- .addReg(LHS)
- .addReg(LHS);
- constrainSelectedInstRegOperands(*Cmp1, TII, TRI, RBI);
- Register Cmp2Reg = MRI->createVirtualRegister(&RISCV::GPRRegClass);
- MachineInstr *Cmp2 =
- BuildMI(*MI.getParent(), MI, MI.getDebugLoc(),
- TII.get(getFCmpOpcode(CmpInst::FCMP_OEQ, Size)), Cmp2Reg)
- .addReg(RHS)
- .addReg(RHS);
- constrainSelectedInstRegOperands(*Cmp2, TII, TRI, RBI);
if (NeedInvert)
TmpReg = MRI->createVirtualRegister(&RISCV::GPRRegClass);
- MachineInstr *And = BuildMI(*MI.getParent(), MI, MI.getDebugLoc(),
- TII.get(RISCV::AND), TmpReg)
- .addReg(Cmp1Reg)
- .addReg(Cmp2Reg);
- constrainSelectedInstRegOperands(*And, TII, TRI, RBI);
+ if (LHS == RHS) {
+ MachineInstr *Cmp =
+ BuildMI(*MI.getParent(), MI, MI.getDebugLoc(),
+ TII.get(getFCmpOpcode(CmpInst::FCMP_OEQ, Size)), TmpReg)
+ .addReg(LHS)
+ .addReg(LHS);
+ constrainSelectedInstRegOperands(*Cmp, TII, TRI, RBI);
+ } else {
+ Register Cmp1Reg = MRI->createVirtualRegister(&RISCV::GPRRegClass);
+ MachineInstr *Cmp1 =
+ BuildMI(*MI.getParent(), MI, MI.getDebugLoc(),
+ TII.get(getFCmpOpcode(CmpInst::FCMP_OEQ, Size)), Cmp1Reg)
+ .addReg(LHS)
+ .addReg(LHS);
+ constrainSelectedInstRegOperands(*Cmp1, TII, TRI, RBI);
+ Register Cmp2Reg = MRI->createVirtualRegister(&RISCV::GPRRegClass);
+ MachineInstr *Cmp2 =
+ BuildMI(*MI.getParent(), MI, MI.getDebugLoc(),
+ TII.get(getFCmpOpcode(CmpInst::FCMP_OEQ, Size)), Cmp2Reg)
+ .addReg(RHS)
+ .addReg(RHS);
+ constrainSelectedInstRegOperands(*Cmp2, TII, TRI, RBI);
+ MachineInstr *And = BuildMI(*MI.getParent(), MI, MI.getDebugLoc(),
+ TII.get(RISCV::AND), TmpReg)
+ .addReg(Cmp1Reg)
+ .addReg(Cmp2Reg);
+ constrainSelectedInstRegOperands(*And, TII, TRI, RBI);
+ }
} else
llvm_unreachable("Unhandled predicate");
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/double-fcmp.ll b/llvm/test/CodeGen/RISCV/GlobalISel/double-fcmp.ll
index ac679cd434d94..fc264d293578b 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/double-fcmp.ll
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/double-fcmp.ll
@@ -592,8 +592,6 @@ define i32 @fcmp_ord_same(double %a) nounwind {
; CHECKIFD-LABEL: fcmp_ord_same:
; CHECKIFD: # %bb.0:
; CHECKIFD-NEXT: feq.d a0, fa0, fa0
-; CHECKIFD-NEXT: feq.d a1, fa0, fa0
-; CHECKIFD-NEXT: and a0, a0, a1
; CHECKIFD-NEXT: ret
;
; RV32I-LABEL: fcmp_ord_same:
@@ -628,8 +626,6 @@ define i32 @fcmp_uno_same(double %a) nounwind {
; CHECKIFD-LABEL: fcmp_uno_same:
; CHECKIFD: # %bb.0:
; CHECKIFD-NEXT: feq.d a0, fa0, fa0
-; CHECKIFD-NEXT: feq.d a1, fa0, fa0
-; CHECKIFD-NEXT: and a0, a0, a1
; CHECKIFD-NEXT: xori a0, a0, 1
; CHECKIFD-NEXT: ret
;
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/float-fcmp.ll b/llvm/test/CodeGen/RISCV/GlobalISel/float-fcmp.ll
index 24e8b0148a39f..825e4134d9e9f 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/float-fcmp.ll
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/float-fcmp.ll
@@ -577,8 +577,6 @@ define i32 @fcmp_ord_same(float %a) nounwind {
; CHECKIF-LABEL: fcmp_ord_same:
; CHECKIF: # %bb.0:
; CHECKIF-NEXT: feq.s a0, fa0, fa0
-; CHECKIF-NEXT: feq.s a1, fa0, fa0
-; CHECKIF-NEXT: and a0, a0, a1
; CHECKIF-NEXT: ret
;
; RV32I-LABEL: fcmp_ord_same:
@@ -612,8 +610,6 @@ define i32 @fcmp_uno_same(float %a) nounwind {
; CHECKIF-LABEL: fcmp_uno_same:
; CHECKIF: # %bb.0:
; CHECKIF-NEXT: feq.s a0, fa0, fa0
-; CHECKIF-NEXT: feq.s a1, fa0, fa0
-; CHECKIF-NEXT: and a0, a0, a1
; CHECKIF-NEXT: xori a0, a0, 1
; CHECKIF-NEXT: ret
;
More information about the llvm-commits
mailing list