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 +}