[llvm] [RISCV][GISel] Use a single FEQ for fcmp ord/uno x, x (PR #192022)

via llvm-commits llvm-commits at lists.llvm.org
Tue Apr 14 01:24:58 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-globalisel

Author: Jim Lin (tclin914)

<details>
<summary>Changes</summary>

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.

---
Full diff: https://github.com/llvm/llvm-project/pull/192022.diff


3 Files Affected:

- (modified) llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp (+29-20) 
- (modified) llvm/test/CodeGen/RISCV/GlobalISel/double-fcmp.ll (+69) 
- (modified) llvm/test/CodeGen/RISCV/GlobalISel/float-fcmp.ll (+67) 


``````````diff
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 9ec8c32e989b0..fc264d293578b 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/double-fcmp.ll
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/double-fcmp.ll
@@ -587,3 +587,72 @@ 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:    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:    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..825e4134d9e9f 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/float-fcmp.ll
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/float-fcmp.ll
@@ -572,3 +572,70 @@ 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:    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:    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
+}

``````````

</details>


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


More information about the llvm-commits mailing list