Skip to content

SelectionDAG: Support nofpclass #108350

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed

Conversation

wzssyqa
Copy link
Contributor

@wzssyqa wzssyqa commented Sep 12, 2024

Currently SelectionDAG ignroes the nofpclass information from arguments. Such as

define dso_local float @f(float noundef nofpclass(nan zero) %a, float noundef nofpclass(nan zero) %b) #0 {
entry:
%cond = tail call float @llvm.maximumnum.f32(float %a, float %b)
ret float %cond
}

In SelectionDAG::isKnownNeverNaN, a false is returned.

TODO:

  1. Add testcase for Inf.

@wzssyqa wzssyqa requested a review from arsenm September 12, 2024 09:11
@llvmbot llvmbot added the llvm:SelectionDAG SelectionDAGISel as well label Sep 12, 2024
@llvmbot
Copy link
Member

llvmbot commented Sep 12, 2024

@llvm/pr-subscribers-backend-amdgpu
@llvm/pr-subscribers-backend-x86
@llvm/pr-subscribers-backend-loongarch

@llvm/pr-subscribers-llvm-selectiondag

Author: YunQiang Su (wzssyqa)

Changes

Currently SelectionDAG ignroes the nofpclass information from arguments. Such as

define dso_local float @f(float noundef nofpclass(nan zero) %a, float noundef nofpclass(nan zero) %b) #0 {
entry:
%cond = tail call float @llvm.maximumnum.f32(float %a, float %b)
ret float %cond
}

In SelectionDAG::isKnownNeverNaN, a false is returned.

TODO:

  1. bool SelectionDAG::isKnownNeverNaN(SDValue Op, bool SNaN, unsigned Depth)
    needs to process hasNoSNaN;
  2. bool SelectionDAG::isKnownNeverZeroFloat(SDValue Op)
    needs to process Zero and SignedZero.
    These 2 problems will be fixed with other PRs.

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

2 Files Affected:

  • (modified) llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp (+8)
  • (modified) llvm/test/CodeGen/Mips/fp-maximumnum-minimumnum.ll (+322)
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 1dbcf8fd765101..49d94706d87d3d 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -11773,6 +11773,14 @@ void SelectionDAGISel::LowerArguments(const Function &F) {
           AssertOp = ISD::AssertSext;
         else if (Arg.hasAttribute(Attribute::ZExt))
           AssertOp = ISD::AssertZext;
+        if (Arg.hasAttribute(Attribute::NoFPClass)) {
+          SDNodeFlags InValFlags = InVals[i]->getFlags();
+          InValFlags.setNonNeg(Arg.getNoFPClass() & llvm::fcNegative);
+          InValFlags.setNoNaNs(Arg.getNoFPClass() & llvm::fcNan);
+          InValFlags.setNoInfs(Arg.getNoFPClass() & llvm::fcInf);
+          InValFlags.setNoSignedZeros(Arg.getNoFPClass() & llvm::fcNegZero);
+          InVals[i]->setFlags(InValFlags);
+        }
 
         ArgValues.push_back(getCopyFromParts(DAG, dl, &InVals[i], NumParts,
                                              PartVT, VT, nullptr, NewRoot,
diff --git a/llvm/test/CodeGen/Mips/fp-maximumnum-minimumnum.ll b/llvm/test/CodeGen/Mips/fp-maximumnum-minimumnum.ll
index bc81966ca0f5c9..92cb05eee27ba7 100644
--- a/llvm/test/CodeGen/Mips/fp-maximumnum-minimumnum.ll
+++ b/llvm/test/CodeGen/Mips/fp-maximumnum-minimumnum.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
 ; RUN: llc --mtriple=mipsisa32r6 < %s | FileCheck %s --check-prefix=MIPS32R6
+; RUN: llc --mtriple=mips64 < %s | FileCheck %s --check-prefix=MIPS64
 
 declare float @llvm.maximumnum.f32(float, float)
 declare double @llvm.maximumnum.f64(double, double)
@@ -13,6 +14,28 @@ define float @maximumnum_float(float %x, float %y) {
 ; MIPS32R6-NEXT:    min.s $f1, $f12, $f12
 ; MIPS32R6-NEXT:    jr $ra
 ; MIPS32R6-NEXT:    max.s $f0, $f1, $f0
+;
+; MIPS64-LABEL: maximumnum_float:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    c.un.s $f12, $f12
+; MIPS64-NEXT:    movt.s $f12, $f13, $fcc0
+; MIPS64-NEXT:    c.un.s $f13, $f13
+; MIPS64-NEXT:    movt.s $f13, $f12, $fcc0
+; MIPS64-NEXT:    c.ule.s $f12, $f13
+; MIPS64-NEXT:    mov.s $f0, $f13
+; MIPS64-NEXT:    movf.s $f0, $f12, $fcc0
+; MIPS64-NEXT:    add.s $f1, $f0, $f0
+; MIPS64-NEXT:    c.un.s $f0, $f0
+; MIPS64-NEXT:    movt.s $f0, $f1, $fcc0
+; MIPS64-NEXT:    mfc1 $1, $f12
+; MIPS64-NEXT:    mov.s $f1, $f0
+; MIPS64-NEXT:    movz.s $f1, $f12, $1
+; MIPS64-NEXT:    mfc1 $1, $f13
+; MIPS64-NEXT:    mtc1 $zero, $f2
+; MIPS64-NEXT:    movz.s $f1, $f13, $1
+; MIPS64-NEXT:    c.eq.s $f0, $f2
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.s $f0, $f1, $fcc0
   %z = call float @llvm.maximumnum.f32(float %x, float %y)
   ret float %z
 }
@@ -24,6 +47,20 @@ define float @maximumnum_float_nsz(float %x, float %y) {
 ; MIPS32R6-NEXT:    min.s $f1, $f12, $f12
 ; MIPS32R6-NEXT:    jr $ra
 ; MIPS32R6-NEXT:    max.s $f0, $f1, $f0
+;
+; MIPS64-LABEL: maximumnum_float_nsz:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    mov.s $f0, $f13
+; MIPS64-NEXT:    c.un.s $f12, $f12
+; MIPS64-NEXT:    movt.s $f12, $f13, $fcc0
+; MIPS64-NEXT:    c.un.s $f13, $f13
+; MIPS64-NEXT:    movt.s $f0, $f12, $fcc0
+; MIPS64-NEXT:    c.ule.s $f12, $f0
+; MIPS64-NEXT:    movf.s $f0, $f12, $fcc0
+; MIPS64-NEXT:    add.s $f1, $f0, $f0
+; MIPS64-NEXT:    c.un.s $f0, $f0
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.s $f0, $f1, $fcc0
   %z = call nsz float @llvm.maximumnum.f32(float %x, float %y)
   ret float %z
 }
@@ -33,10 +70,48 @@ define float @maximumnum_float_nnan(float %x, float %y) {
 ; MIPS32R6:       # %bb.0:
 ; MIPS32R6-NEXT:    jr $ra
 ; MIPS32R6-NEXT:    max.s $f0, $f12, $f14
+;
+; MIPS64-LABEL: maximumnum_float_nnan:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    c.ule.s $f12, $f13
+; MIPS64-NEXT:    mov.s $f0, $f13
+; MIPS64-NEXT:    movf.s $f0, $f12, $fcc0
+; MIPS64-NEXT:    mfc1 $1, $f12
+; MIPS64-NEXT:    mov.s $f1, $f0
+; MIPS64-NEXT:    movz.s $f1, $f12, $1
+; MIPS64-NEXT:    mfc1 $1, $f13
+; MIPS64-NEXT:    movz.s $f1, $f13, $1
+; MIPS64-NEXT:    mtc1 $zero, $f2
+; MIPS64-NEXT:    c.eq.s $f0, $f2
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.s $f0, $f1, $fcc0
   %z = call nnan float @llvm.maximumnum.f32(float %x, float %y)
   ret float %z
 }
 
+define float @maximumnum_float_nnan_arg(float nofpclass(nan) %x, float nofpclass(nan) %y) {
+; MIPS32R6-LABEL: maximumnum_float_nnan_arg:
+; MIPS32R6:       # %bb.0:
+; MIPS32R6-NEXT:    jr $ra
+; MIPS32R6-NEXT:    max.s $f0, $f12, $f14
+;
+; MIPS64-LABEL: maximumnum_float_nnan_arg:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    c.ule.s $f12, $f13
+; MIPS64-NEXT:    mov.s $f0, $f13
+; MIPS64-NEXT:    movf.s $f0, $f12, $fcc0
+; MIPS64-NEXT:    mfc1 $1, $f12
+; MIPS64-NEXT:    mov.s $f1, $f0
+; MIPS64-NEXT:    movz.s $f1, $f12, $1
+; MIPS64-NEXT:    mfc1 $1, $f13
+; MIPS64-NEXT:    movz.s $f1, $f13, $1
+; MIPS64-NEXT:    mtc1 $zero, $f2
+; MIPS64-NEXT:    c.eq.s $f0, $f2
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.s $f0, $f1, $fcc0
+  %z = call float @llvm.maximumnum.f32(float %x, float %y)
+  ret float %z
+}
 
 define double @maximumnum_double(double %x, double %y) {
 ; MIPS32R6-LABEL: maximumnum_double:
@@ -45,6 +120,28 @@ define double @maximumnum_double(double %x, double %y) {
 ; MIPS32R6-NEXT:    min.d $f1, $f12, $f12
 ; MIPS32R6-NEXT:    jr $ra
 ; MIPS32R6-NEXT:    max.d $f0, $f1, $f0
+;
+; MIPS64-LABEL: maximumnum_double:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    c.un.d $f12, $f12
+; MIPS64-NEXT:    movt.d $f12, $f13, $fcc0
+; MIPS64-NEXT:    c.un.d $f13, $f13
+; MIPS64-NEXT:    movt.d $f13, $f12, $fcc0
+; MIPS64-NEXT:    c.ule.d $f12, $f13
+; MIPS64-NEXT:    mov.d $f0, $f13
+; MIPS64-NEXT:    movf.d $f0, $f12, $fcc0
+; MIPS64-NEXT:    add.d $f1, $f0, $f0
+; MIPS64-NEXT:    c.un.d $f0, $f0
+; MIPS64-NEXT:    movt.d $f0, $f1, $fcc0
+; MIPS64-NEXT:    dmfc1 $1, $f12
+; MIPS64-NEXT:    mov.d $f1, $f0
+; MIPS64-NEXT:    movz.d $f1, $f12, $1
+; MIPS64-NEXT:    dmfc1 $1, $f13
+; MIPS64-NEXT:    movz.d $f1, $f13, $1
+; MIPS64-NEXT:    dmtc1 $zero, $f2
+; MIPS64-NEXT:    c.eq.d $f0, $f2
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.d $f0, $f1, $fcc0
   %z = call double @llvm.maximumnum.f64(double %x, double %y)
   ret double %z
 }
@@ -56,6 +153,20 @@ define double @maximumnum_double_nsz(double %x, double %y) {
 ; MIPS32R6-NEXT:    min.d $f1, $f12, $f12
 ; MIPS32R6-NEXT:    jr $ra
 ; MIPS32R6-NEXT:    max.d $f0, $f1, $f0
+;
+; MIPS64-LABEL: maximumnum_double_nsz:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    mov.d $f0, $f13
+; MIPS64-NEXT:    c.un.d $f12, $f12
+; MIPS64-NEXT:    movt.d $f12, $f13, $fcc0
+; MIPS64-NEXT:    c.un.d $f13, $f13
+; MIPS64-NEXT:    movt.d $f0, $f12, $fcc0
+; MIPS64-NEXT:    c.ule.d $f12, $f0
+; MIPS64-NEXT:    movf.d $f0, $f12, $fcc0
+; MIPS64-NEXT:    add.d $f1, $f0, $f0
+; MIPS64-NEXT:    c.un.d $f0, $f0
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.d $f0, $f1, $fcc0
   %z = call nsz double @llvm.maximumnum.f64(double %x, double %y)
   ret double %z
 }
@@ -65,10 +176,49 @@ define double @maximumnum_double_nnan(double %x, double %y) {
 ; MIPS32R6:       # %bb.0:
 ; MIPS32R6-NEXT:    jr $ra
 ; MIPS32R6-NEXT:    max.d $f0, $f12, $f14
+;
+; MIPS64-LABEL: maximumnum_double_nnan:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    c.ule.d $f12, $f13
+; MIPS64-NEXT:    mov.d $f0, $f13
+; MIPS64-NEXT:    movf.d $f0, $f12, $fcc0
+; MIPS64-NEXT:    dmfc1 $1, $f12
+; MIPS64-NEXT:    mov.d $f1, $f0
+; MIPS64-NEXT:    movz.d $f1, $f12, $1
+; MIPS64-NEXT:    dmfc1 $1, $f13
+; MIPS64-NEXT:    movz.d $f1, $f13, $1
+; MIPS64-NEXT:    dmtc1 $zero, $f2
+; MIPS64-NEXT:    c.eq.d $f0, $f2
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.d $f0, $f1, $fcc0
   %z = call nnan double @llvm.maximumnum.f64(double %x, double %y)
   ret double %z
 }
 
+define double @maximumnum_double_nnan_arg(double nofpclass(nan) %x, double nofpclass(nan) %y) {
+; MIPS32R6-LABEL: maximumnum_double_nnan_arg:
+; MIPS32R6:       # %bb.0:
+; MIPS32R6-NEXT:    jr $ra
+; MIPS32R6-NEXT:    max.d $f0, $f12, $f14
+;
+; MIPS64-LABEL: maximumnum_double_nnan_arg:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    c.ule.d $f12, $f13
+; MIPS64-NEXT:    mov.d $f0, $f13
+; MIPS64-NEXT:    movf.d $f0, $f12, $fcc0
+; MIPS64-NEXT:    dmfc1 $1, $f12
+; MIPS64-NEXT:    mov.d $f1, $f0
+; MIPS64-NEXT:    movz.d $f1, $f12, $1
+; MIPS64-NEXT:    dmfc1 $1, $f13
+; MIPS64-NEXT:    movz.d $f1, $f13, $1
+; MIPS64-NEXT:    dmtc1 $zero, $f2
+; MIPS64-NEXT:    c.eq.d $f0, $f2
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.d $f0, $f1, $fcc0
+  %z = call double @llvm.maximumnum.f64(double %x, double %y)
+  ret double %z
+}
+
 define float @minimumnum_float(float %x, float %y) {
 ; MIPS32R6-LABEL: minimumnum_float:
 ; MIPS32R6:       # %bb.0:
@@ -76,6 +226,31 @@ define float @minimumnum_float(float %x, float %y) {
 ; MIPS32R6-NEXT:    min.s $f1, $f12, $f12
 ; MIPS32R6-NEXT:    jr $ra
 ; MIPS32R6-NEXT:    min.s $f0, $f1, $f0
+;
+; MIPS64-LABEL: minimumnum_float:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    c.un.s $f12, $f12
+; MIPS64-NEXT:    movt.s $f12, $f13, $fcc0
+; MIPS64-NEXT:    c.un.s $f13, $f13
+; MIPS64-NEXT:    movt.s $f13, $f12, $fcc0
+; MIPS64-NEXT:    c.olt.s $f12, $f13
+; MIPS64-NEXT:    mov.s $f0, $f13
+; MIPS64-NEXT:    movt.s $f0, $f12, $fcc0
+; MIPS64-NEXT:    add.s $f1, $f0, $f0
+; MIPS64-NEXT:    c.un.s $f0, $f0
+; MIPS64-NEXT:    movt.s $f0, $f1, $fcc0
+; MIPS64-NEXT:    mfc1 $1, $f12
+; MIPS64-NEXT:    lui $2, 32768
+; MIPS64-NEXT:    xor $1, $1, $2
+; MIPS64-NEXT:    mov.s $f1, $f0
+; MIPS64-NEXT:    movz.s $f1, $f12, $1
+; MIPS64-NEXT:    mfc1 $1, $f13
+; MIPS64-NEXT:    xor $1, $1, $2
+; MIPS64-NEXT:    mtc1 $zero, $f2
+; MIPS64-NEXT:    movz.s $f1, $f13, $1
+; MIPS64-NEXT:    c.eq.s $f0, $f2
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.s $f0, $f1, $fcc0
   %z = call float @llvm.minimumnum.f32(float %x, float %y)
   ret float %z
 }
@@ -87,6 +262,20 @@ define float @minimumnum_float_nsz(float %x, float %y) {
 ; MIPS32R6-NEXT:    min.s $f1, $f12, $f12
 ; MIPS32R6-NEXT:    jr $ra
 ; MIPS32R6-NEXT:    min.s $f0, $f1, $f0
+;
+; MIPS64-LABEL: minimumnum_float_nsz:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    mov.s $f0, $f13
+; MIPS64-NEXT:    c.un.s $f12, $f12
+; MIPS64-NEXT:    movt.s $f12, $f13, $fcc0
+; MIPS64-NEXT:    c.un.s $f13, $f13
+; MIPS64-NEXT:    movt.s $f0, $f12, $fcc0
+; MIPS64-NEXT:    c.olt.s $f12, $f0
+; MIPS64-NEXT:    movt.s $f0, $f12, $fcc0
+; MIPS64-NEXT:    add.s $f1, $f0, $f0
+; MIPS64-NEXT:    c.un.s $f0, $f0
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.s $f0, $f1, $fcc0
   %z = call nsz float @llvm.minimumnum.f32(float %x, float %y)
   ret float %z
 }
@@ -96,10 +285,56 @@ define float @minimumnum_float_nnan(float %x, float %y) {
 ; MIPS32R6:       # %bb.0:
 ; MIPS32R6-NEXT:    jr $ra
 ; MIPS32R6-NEXT:    min.s $f0, $f12, $f14
+;
+; MIPS64-LABEL: minimumnum_float_nnan:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    c.olt.s $f12, $f13
+; MIPS64-NEXT:    mov.s $f0, $f13
+; MIPS64-NEXT:    movt.s $f0, $f12, $fcc0
+; MIPS64-NEXT:    mfc1 $1, $f12
+; MIPS64-NEXT:    lui $2, 32768
+; MIPS64-NEXT:    xor $1, $1, $2
+; MIPS64-NEXT:    mov.s $f1, $f0
+; MIPS64-NEXT:    movz.s $f1, $f12, $1
+; MIPS64-NEXT:    mfc1 $1, $f13
+; MIPS64-NEXT:    xor $1, $1, $2
+; MIPS64-NEXT:    movz.s $f1, $f13, $1
+; MIPS64-NEXT:    mtc1 $zero, $f2
+; MIPS64-NEXT:    c.eq.s $f0, $f2
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.s $f0, $f1, $fcc0
+  %z = call nnan float @llvm.minimumnum.f32(float %x, float %y)
+  ret float %z
+}
+
+define float @minimumnum_float_nnan_arg(float nofpclass(nan) %x, float nofpclass(nan) %y) {
+; MIPS32R6-LABEL: minimumnum_float_nnan_arg:
+; MIPS32R6:       # %bb.0:
+; MIPS32R6-NEXT:    jr $ra
+; MIPS32R6-NEXT:    min.s $f0, $f12, $f14
+;
+; MIPS64-LABEL: minimumnum_float_nnan_arg:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    c.olt.s $f12, $f13
+; MIPS64-NEXT:    mov.s $f0, $f13
+; MIPS64-NEXT:    movt.s $f0, $f12, $fcc0
+; MIPS64-NEXT:    mfc1 $1, $f12
+; MIPS64-NEXT:    lui $2, 32768
+; MIPS64-NEXT:    xor $1, $1, $2
+; MIPS64-NEXT:    mov.s $f1, $f0
+; MIPS64-NEXT:    movz.s $f1, $f12, $1
+; MIPS64-NEXT:    mfc1 $1, $f13
+; MIPS64-NEXT:    xor $1, $1, $2
+; MIPS64-NEXT:    movz.s $f1, $f13, $1
+; MIPS64-NEXT:    mtc1 $zero, $f2
+; MIPS64-NEXT:    c.eq.s $f0, $f2
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.s $f0, $f1, $fcc0
   %z = call nnan float @llvm.minimumnum.f32(float %x, float %y)
   ret float %z
 }
 
+
 define double @minimumnum_double(double %x, double %y) {
 ; MIPS32R6-LABEL: minimumnum_double:
 ; MIPS32R6:       # %bb.0:
@@ -107,6 +342,32 @@ define double @minimumnum_double(double %x, double %y) {
 ; MIPS32R6-NEXT:    min.d $f1, $f12, $f12
 ; MIPS32R6-NEXT:    jr $ra
 ; MIPS32R6-NEXT:    min.d $f0, $f1, $f0
+;
+; MIPS64-LABEL: minimumnum_double:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    c.un.d $f12, $f12
+; MIPS64-NEXT:    movt.d $f12, $f13, $fcc0
+; MIPS64-NEXT:    c.un.d $f13, $f13
+; MIPS64-NEXT:    movt.d $f13, $f12, $fcc0
+; MIPS64-NEXT:    c.olt.d $f12, $f13
+; MIPS64-NEXT:    mov.d $f0, $f13
+; MIPS64-NEXT:    movt.d $f0, $f12, $fcc0
+; MIPS64-NEXT:    add.d $f1, $f0, $f0
+; MIPS64-NEXT:    c.un.d $f0, $f0
+; MIPS64-NEXT:    movt.d $f0, $f1, $fcc0
+; MIPS64-NEXT:    dmfc1 $1, $f12
+; MIPS64-NEXT:    daddiu $2, $zero, 1
+; MIPS64-NEXT:    dsll $2, $2, 63
+; MIPS64-NEXT:    xor $1, $1, $2
+; MIPS64-NEXT:    mov.d $f1, $f0
+; MIPS64-NEXT:    movz.d $f1, $f12, $1
+; MIPS64-NEXT:    dmfc1 $1, $f13
+; MIPS64-NEXT:    xor $1, $1, $2
+; MIPS64-NEXT:    movz.d $f1, $f13, $1
+; MIPS64-NEXT:    dmtc1 $zero, $f2
+; MIPS64-NEXT:    c.eq.d $f0, $f2
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.d $f0, $f1, $fcc0
   %z = call double @llvm.minimumnum.f64(double %x, double %y)
   ret double %z
 }
@@ -118,6 +379,20 @@ define double @minimumnum_double_nsz(double %x, double %y) {
 ; MIPS32R6-NEXT:    min.d $f1, $f12, $f12
 ; MIPS32R6-NEXT:    jr $ra
 ; MIPS32R6-NEXT:    min.d $f0, $f1, $f0
+;
+; MIPS64-LABEL: minimumnum_double_nsz:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    mov.d $f0, $f13
+; MIPS64-NEXT:    c.un.d $f12, $f12
+; MIPS64-NEXT:    movt.d $f12, $f13, $fcc0
+; MIPS64-NEXT:    c.un.d $f13, $f13
+; MIPS64-NEXT:    movt.d $f0, $f12, $fcc0
+; MIPS64-NEXT:    c.olt.d $f12, $f0
+; MIPS64-NEXT:    movt.d $f0, $f12, $fcc0
+; MIPS64-NEXT:    add.d $f1, $f0, $f0
+; MIPS64-NEXT:    c.un.d $f0, $f0
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.d $f0, $f1, $fcc0
   %z = call nsz double @llvm.minimumnum.f64(double %x, double %y)
   ret double %z
 }
@@ -127,6 +402,53 @@ define double @minimumnum_double_nnan(double %x, double %y) {
 ; MIPS32R6:       # %bb.0:
 ; MIPS32R6-NEXT:    jr $ra
 ; MIPS32R6-NEXT:    min.d $f0, $f12, $f14
+;
+; MIPS64-LABEL: minimumnum_double_nnan:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    c.olt.d $f12, $f13
+; MIPS64-NEXT:    mov.d $f0, $f13
+; MIPS64-NEXT:    movt.d $f0, $f12, $fcc0
+; MIPS64-NEXT:    daddiu $1, $zero, 1
+; MIPS64-NEXT:    dsll $1, $1, 63
+; MIPS64-NEXT:    dmfc1 $2, $f12
+; MIPS64-NEXT:    xor $2, $2, $1
+; MIPS64-NEXT:    mov.d $f1, $f0
+; MIPS64-NEXT:    movz.d $f1, $f12, $2
+; MIPS64-NEXT:    dmfc1 $2, $f13
+; MIPS64-NEXT:    xor $1, $2, $1
+; MIPS64-NEXT:    movz.d $f1, $f13, $1
+; MIPS64-NEXT:    dmtc1 $zero, $f2
+; MIPS64-NEXT:    c.eq.d $f0, $f2
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.d $f0, $f1, $fcc0
+  %z = call nnan double @llvm.minimumnum.f64(double %x, double %y)
+  ret double %z
+}
+
+define double @minimumnum_double_nnan_arg(double nofpclass(nan) %x, double nofpclass(nan) %y) {
+; MIPS32R6-LABEL: minimumnum_double_nnan_arg:
+; MIPS32R6:       # %bb.0:
+; MIPS32R6-NEXT:    jr $ra
+; MIPS32R6-NEXT:    min.d $f0, $f12, $f14
+;
+; MIPS64-LABEL: minimumnum_double_nnan_arg:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    c.olt.d $f12, $f13
+; MIPS64-NEXT:    mov.d $f0, $f13
+; MIPS64-NEXT:    movt.d $f0, $f12, $fcc0
+; MIPS64-NEXT:    daddiu $1, $zero, 1
+; MIPS64-NEXT:    dsll $1, $1, 63
+; MIPS64-NEXT:    dmfc1 $2, $f12
+; MIPS64-NEXT:    xor $2, $2, $1
+; MIPS64-NEXT:    mov.d $f1, $f0
+; MIPS64-NEXT:    movz.d $f1, $f12, $2
+; MIPS64-NEXT:    dmfc1 $2, $f13
+; MIPS64-NEXT:    xor $1, $2, $1
+; MIPS64-NEXT:    movz.d $f1, $f13, $1
+; MIPS64-NEXT:    dmtc1 $zero, $f2
+; MIPS64-NEXT:    c.eq.d $f0, $f2
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.d $f0, $f1, $fcc0
   %z = call nnan double @llvm.minimumnum.f64(double %x, double %y)
   ret double %z
 }

ret float %z
}

define float @minimumnum_float_nnan_arg(float nofpclass(nan) %x, float nofpclass(nan) %y) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tests won't cover the inf case. You also should test the separate nofpclass(qnan) and nofpclass(snan) cases, which individually are not strong enough to set the corresponding flag

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you have any idea about cases for inf?
I cannot find one, and we have no isKnownNeverInf() at all.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The FP tracking code in SelectionDAG is quite poor, and it's a lot of effort to reimplement computeKnownFPClass in SDAG/GlobalISel. We only have stub implementations of isKnownNeverZeroFloat, isKnownNeverNaN, and cannotBeOrderedNegativeFP

; MIPS64-NEXT: c.eq.s $f0, $f2
; MIPS64-NEXT: jr $ra
; MIPS64-NEXT: movt.s $f0, $f1, $fcc0
%z = call nnan float @llvm.minimumnum.f32(float %x, float %y)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer to test these with some simpler to understand operation than minimumnum. Is there some other fold that doesn't involve any flavor of fmin?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can only find there is only one about FP_TO_BF16.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fcmp + select to min variant would be more straightforward

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a try fcmp + select with this IR

define dso_local noundef float @max(float noundef nofpclass(nan) %a, float noundef nofpclass(nan) %b) local_unnamed_addr #0 {
entry:
  %cmp = fcmp ogt float %a, %b
  %cond = select i1 %cmp, float %a, float %b
  ret float %cond
}

It is not easy to support it. The problem is that the argument of void SelectionDAGBuilder::visitSelect(const User &I)
is marked as const, so we have no chance to edit I if we detect the both LHS and RHS are nnan.

And then visitSelect calls

SelectPatternResult llvm::matchDecomposedSelectPattern(
    CmpInst *CmpI, Value *TrueVal, Value *FalseVal, Value *&LHS, Value *&RHS,
    Instruction::CastOps *CastOp, unsigned Depth)

It may be not a good idea to use the methods from SelectionDAG there.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@arsenm #109570 To use fcmp+select, we need this PR first.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use other incoming instructions with nnan flags, this PR is not necessary for test coverage

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use other incoming instructions with nnan flags, this PR is not necessary for test coverage

ISD::SELECT seems ignoring nnan.

Copy link
Contributor

@arsenm arsenm Oct 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Means there's a flag dropped or SelectionDAG never learned about select flags. Try something like an fadd? Probably a bug somewhere

Currently SelectionDAG ignroes the nofpclass information from arguments.
Such as

   define dso_local float @f(float noundef nofpclass(nan zero) %a, float noundef nofpclass(nan zero) %b) #0 {
       entry:
       %cond = tail call float @llvm.maximumnum.f32(float %a, float %b)
       ret float %cond
   }

In SelectionDAG::isKnownNeverNaN, a false is returned.

TODO:
1) bool SelectionDAG::isKnownNeverNaN(SDValue Op, bool SNaN, unsigned Depth)
   needs to process hasNoSNaN;
2) bool SelectionDAG::isKnownNeverZeroFloat(SDValue Op)
   needs to process Zero and SignedZero.
These 2 problems will be fixed with other PRs.
@wzssyqa wzssyqa marked this pull request as draft September 22, 2024 07:18
Copy link
Contributor

@arsenm arsenm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the way to handle this in general is introduce an AssertNoFPClass, similar to AssertZext etc.

@wzssyqa
Copy link
Contributor Author

wzssyqa commented Apr 16, 2025

Replaced by: #130051

@wzssyqa wzssyqa closed this Apr 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants