[llvm] [SystemZ] Add support for strict_pseudo_fmin/fmax (PR #209434)

via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 14 03:49:31 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-systemz

Author: Nikita Popov (nikic)

<details>
<summary>Changes</summary>

Mode 2 of vfmin/vfmax is also compatible with strict semantics (producing invalid operation exception for both qNaN and sNaN and returning RHS if masked.)

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


5 Files Affected:

- (modified) llvm/include/llvm/Target/TargetSelectionDAG.td (+6) 
- (modified) llvm/lib/Target/SystemZ/SystemZISelLowering.cpp (+2) 
- (modified) llvm/lib/Target/SystemZ/SystemZInstrVector.td (+2-2) 
- (added) llvm/test/CodeGen/SystemZ/vec-strict-pseudo-max.ll (+145) 
- (added) llvm/test/CodeGen/SystemZ/vec-strict-pseudo-min.ll (+145) 


``````````diff
diff --git a/llvm/include/llvm/Target/TargetSelectionDAG.td b/llvm/include/llvm/Target/TargetSelectionDAG.td
index 4e3c099f1714d..69be608107359 100644
--- a/llvm/include/llvm/Target/TargetSelectionDAG.td
+++ b/llvm/include/llvm/Target/TargetSelectionDAG.td
@@ -1911,6 +1911,12 @@ def any_fmaximum   : PatFrags<(ops node:$lhs, node:$rhs),
 def any_fminimum   : PatFrags<(ops node:$lhs, node:$rhs),
                               [(strict_fminimum node:$lhs, node:$rhs),
                                (fminimum node:$lhs, node:$rhs)]>;
+def any_pseudo_fmax : PatFrags<(ops node:$lhs, node:$rhs),
+                              [(strict_pseudo_fmax node:$lhs, node:$rhs),
+                               (pseudo_fmax node:$lhs, node:$rhs)]>;
+def any_pseudo_fmin : PatFrags<(ops node:$lhs, node:$rhs),
+                              [(strict_pseudo_fmin node:$lhs, node:$rhs),
+                               (pseudo_fmin node:$lhs, node:$rhs)]>;
 def any_fpround    : PatFrags<(ops node:$src),
                               [(strict_fpround node:$src),
                                (fpround node:$src)]>;
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index 913ddee6637c9..ecf8131a023c0 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -725,6 +725,8 @@ SystemZTargetLowering::SystemZTargetLowering(const TargetMachine &TM,
       setOperationAction(ISD::STRICT_FMINNUM, VT, Legal);
       setOperationAction(ISD::STRICT_FMAXIMUM, VT, Legal);
       setOperationAction(ISD::STRICT_FMINIMUM, VT, Legal);
+      setOperationAction(ISD::STRICT_PSEUDO_FMAX, VT, Legal);
+      setOperationAction(ISD::STRICT_PSEUDO_FMIN, VT, Legal);
     }
   }
 
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrVector.td b/llvm/lib/Target/SystemZ/SystemZInstrVector.td
index 503a55dfe717b..c614af8b295c4 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrVector.td
+++ b/llvm/lib/Target/SystemZ/SystemZInstrVector.td
@@ -1626,7 +1626,7 @@ let Predicates = [FeatureVector] in {
     def : FPMinMax<insn, any_fmaxnum, tr, 4>;
     def : FPMinMax<insn, fmaximumnum, tr, 4>;
     def : FPMinMax<insn, any_fmaximum, tr, 1>;
-    def : FPMinMax<insn, pseudo_fmax, tr, 2>;
+    def : FPMinMax<insn, any_pseudo_fmax, tr, 2>;
   }
   let Predicates = [FeatureVectorEnhancements1] in {
     let Uses = [FPC], mayRaiseFPException = 1, isCommutable = 1 in {
@@ -1654,7 +1654,7 @@ let Predicates = [FeatureVector] in {
     def : FPMinMax<insn, any_fminnum, tr, 4>;
     def : FPMinMax<insn, fminimumnum, tr, 4>;
     def : FPMinMax<insn, any_fminimum, tr, 1>;
-    def : FPMinMax<insn, pseudo_fmin, tr, 2>;
+    def : FPMinMax<insn, any_pseudo_fmin, tr, 2>;
   }
   let Predicates = [FeatureVectorEnhancements1] in {
     let Uses = [FPC], mayRaiseFPException = 1, isCommutable = 1 in {
diff --git a/llvm/test/CodeGen/SystemZ/vec-strict-pseudo-max.ll b/llvm/test/CodeGen/SystemZ/vec-strict-pseudo-max.ll
new file mode 100644
index 0000000000000..928e65929c82f
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/vec-strict-pseudo-max.ll
@@ -0,0 +1,145 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z14 | FileCheck %s
+
+define float @pseudo_fmax_float(float %x, float %y) strictfp {
+; CHECK-LABEL: pseudo_fmax_float:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    wfmaxsb %f0, %f0, %f2, 2
+; CHECK-NEXT:    br %r14
+  %cmp = call i1 @llvm.experimental.constrained.fcmps(float %x, float %y, metadata !"ogt", metadata !"fpexcept.strict") strictfp
+  %sel = select i1 %cmp, float %x, float %y
+  ret float %sel
+}
+
+define float @pseudo_fmax_float_wrong_fcmp(float %x, float %y) strictfp {
+; CHECK-LABEL: pseudo_fmax_float_wrong_fcmp:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cebr %f0, %f2
+; CHECK-NEXT:    bhr %r14
+; CHECK-NEXT:  .LBB1_1:
+; CHECK-NEXT:    ldr %f0, %f2
+; CHECK-NEXT:    br %r14
+  %cmp = call i1 @llvm.experimental.constrained.fcmp(float %x, float %y, metadata !"ogt", metadata !"fpexcept.strict") strictfp
+  %sel = select i1 %cmp, float %x, float %y
+  ret float %sel
+}
+
+define float @pseudo_fmax_float_wrong_pred1(float %x, float %y) strictfp {
+; CHECK-LABEL: pseudo_fmax_float_wrong_pred1:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    kebr %f0, %f2
+; CHECK-NEXT:    bher %r14
+; CHECK-NEXT:  .LBB2_1:
+; CHECK-NEXT:    ldr %f0, %f2
+; CHECK-NEXT:    br %r14
+  %cmp = call i1 @llvm.experimental.constrained.fcmps(float %x, float %y, metadata !"oge", metadata !"fpexcept.strict") strictfp
+  %sel = select i1 %cmp, float %x, float %y
+  ret float %sel
+}
+
+define float @pseudo_fmax_float_wrong_pred2(float %x, float %y) strictfp {
+; CHECK-LABEL: pseudo_fmax_float_wrong_pred2:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    kebr %f0, %f2
+; CHECK-NEXT:    bnler %r14
+; CHECK-NEXT:  .LBB3_1:
+; CHECK-NEXT:    ldr %f0, %f2
+; CHECK-NEXT:    br %r14
+  %cmp = call i1 @llvm.experimental.constrained.fcmps(float %x, float %y, metadata !"ugt", metadata !"fpexcept.strict") strictfp
+  %sel = select i1 %cmp, float %x, float %y
+  ret float %sel
+}
+
+define double @pseudo_fmax_double(double %x, double %y) strictfp {
+; CHECK-LABEL: pseudo_fmax_double:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    wfmaxdb %f0, %f0, %f2, 2
+; CHECK-NEXT:    br %r14
+  %cmp = call i1 @llvm.experimental.constrained.fcmps(double %x, double %y, metadata !"ogt", metadata !"fpexcept.strict") strictfp
+  %sel = select i1 %cmp, double %x, double %y
+  ret double %sel
+}
+
+define fp128 @pseudo_fmax_fp128(fp128 %x, fp128 %y) strictfp {
+; CHECK-LABEL: pseudo_fmax_fp128:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vl %v0, 0(%r4), 3
+; CHECK-NEXT:    vl %v1, 0(%r3), 3
+; CHECK-NEXT:    wfmaxxb %v0, %v1, %v0, 2
+; CHECK-NEXT:    vst %v0, 0(%r2), 3
+; CHECK-NEXT:    br %r14
+  %cmp = call i1 @llvm.experimental.constrained.fcmps(fp128 %x, fp128 %y, metadata !"ogt", metadata !"fpexcept.strict") strictfp
+  %sel = select i1 %cmp, fp128 %x, fp128 %y
+  ret fp128 %sel
+}
+
+define half @pseudo_fmax_half(half %x, half %y) strictfp nounwind {
+; CHECK-LABEL: pseudo_fmax_half:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    stmg %r14, %r15, 112(%r15)
+; CHECK-NEXT:    aghi %r15, -192
+; CHECK-NEXT:    std %f8, 184(%r15) # 8-byte Spill
+; CHECK-NEXT:    std %f9, 176(%r15) # 8-byte Spill
+; CHECK-NEXT:    std %f10, 168(%r15) # 8-byte Spill
+; CHECK-NEXT:    std %f11, 160(%r15) # 8-byte Spill
+; CHECK-NEXT:    ldr %f8, %f0
+; CHECK-NEXT:    ldr %f0, %f2
+; CHECK-NEXT:    ldr %f9, %f2
+; CHECK-NEXT:    brasl %r14, __extendhfsf2 at PLT
+; CHECK-NEXT:    ldr %f10, %f0
+; CHECK-NEXT:    ldr %f0, %f8
+; CHECK-NEXT:    brasl %r14, __extendhfsf2 at PLT
+; CHECK-NEXT:    ldr %f11, %f0
+; CHECK-NEXT:    ldr %f0, %f8
+; CHECK-NEXT:    brasl %r14, __extendhfsf2 at PLT
+; CHECK-NEXT:    ldr %f8, %f0
+; CHECK-NEXT:    ldr %f0, %f9
+; CHECK-NEXT:    brasl %r14, __extendhfsf2 at PLT
+; CHECK-NEXT:    kebr %f11, %f10
+; CHECK-NEXT:    jh .LBB6_2
+; CHECK-NEXT:  # %bb.1:
+; CHECK-NEXT:    ldr %f8, %f0
+; CHECK-NEXT:  .LBB6_2:
+; CHECK-NEXT:    ldr %f0, %f8
+; CHECK-NEXT:    brasl %r14, __truncsfhf2 at PLT
+; CHECK-NEXT:    ld %f8, 184(%r15) # 8-byte Reload
+; CHECK-NEXT:    ld %f9, 176(%r15) # 8-byte Reload
+; CHECK-NEXT:    ld %f10, 168(%r15) # 8-byte Reload
+; CHECK-NEXT:    ld %f11, 160(%r15) # 8-byte Reload
+; CHECK-NEXT:    lmg %r14, %r15, 304(%r15)
+; CHECK-NEXT:    br %r14
+  %cmp = call i1 @llvm.experimental.constrained.fcmps(half %x, half %y, metadata !"ogt", metadata !"fpexcept.strict") strictfp
+  %sel = select i1 %cmp, half %x, half %y
+  ret half %sel
+}
+
+define <4 x float> @pseudo_fmax_v4f32(<4 x float> %x, <4 x float> %y) strictfp {
+; CHECK-LABEL: pseudo_fmax_v4f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vfmaxsb %v24, %v24, %v26, 2
+; CHECK-NEXT:    br %r14
+  %cmp = call <4 x i1> @llvm.experimental.constrained.fcmps(<4 x float> %x, <4 x float> %y, metadata !"ogt", metadata !"fpexcept.strict") strictfp
+  %sel = select <4 x i1> %cmp, <4 x float> %x, <4 x float> %y
+  ret <4 x float> %sel
+}
+
+define <2 x double> @pseudo_fmax_v2f64(<2 x double> %x, <2 x double> %y) strictfp {
+; CHECK-LABEL: pseudo_fmax_v2f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vfmaxdb %v24, %v24, %v26, 2
+; CHECK-NEXT:    br %r14
+  %cmp = call <2 x i1> @llvm.experimental.constrained.fcmps(<2 x double> %x, <2 x double> %y, metadata !"ogt", metadata !"fpexcept.strict") strictfp
+  %sel = select <2 x i1> %cmp, <2 x double> %x, <2 x double> %y
+  ret <2 x double> %sel
+}
+
+define <4 x double> @pseudo_fmax_v4f64(<4 x double> %x, <4 x double> %y) strictfp {
+; CHECK-LABEL: pseudo_fmax_v4f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vfmaxdb %v24, %v24, %v28, 2
+; CHECK-NEXT:    vfmaxdb %v26, %v26, %v30, 2
+; CHECK-NEXT:    br %r14
+  %cmp = call <4 x i1> @llvm.experimental.constrained.fcmps(<4 x double> %x, <4 x double> %y, metadata !"ogt", metadata !"fpexcept.strict") strictfp
+  %sel = select <4 x i1> %cmp, <4 x double> %x, <4 x double> %y
+  ret <4 x double> %sel
+}
diff --git a/llvm/test/CodeGen/SystemZ/vec-strict-pseudo-min.ll b/llvm/test/CodeGen/SystemZ/vec-strict-pseudo-min.ll
new file mode 100644
index 0000000000000..5ff774841fb98
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/vec-strict-pseudo-min.ll
@@ -0,0 +1,145 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z14 | FileCheck %s
+
+define float @pseudo_fmin_float(float %x, float %y) strictfp {
+; CHECK-LABEL: pseudo_fmin_float:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    wfminsb %f0, %f0, %f2, 2
+; CHECK-NEXT:    br %r14
+  %cmp = call i1 @llvm.experimental.constrained.fcmps(float %x, float %y, metadata !"olt", metadata !"fpexcept.strict") strictfp
+  %sel = select i1 %cmp, float %x, float %y
+  ret float %sel
+}
+
+define float @pseudo_fmin_float_wrong_fcmp(float %x, float %y) strictfp {
+; CHECK-LABEL: pseudo_fmin_float_wrong_fcmp:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cebr %f0, %f2
+; CHECK-NEXT:    blr %r14
+; CHECK-NEXT:  .LBB1_1:
+; CHECK-NEXT:    ldr %f0, %f2
+; CHECK-NEXT:    br %r14
+  %cmp = call i1 @llvm.experimental.constrained.fcmp(float %x, float %y, metadata !"olt", metadata !"fpexcept.strict") strictfp
+  %sel = select i1 %cmp, float %x, float %y
+  ret float %sel
+}
+
+define float @pseudo_fmin_float_wrong_pred1(float %x, float %y) strictfp {
+; CHECK-LABEL: pseudo_fmin_float_wrong_pred1:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    kebr %f0, %f2
+; CHECK-NEXT:    bler %r14
+; CHECK-NEXT:  .LBB2_1:
+; CHECK-NEXT:    ldr %f0, %f2
+; CHECK-NEXT:    br %r14
+  %cmp = call i1 @llvm.experimental.constrained.fcmps(float %x, float %y, metadata !"ole", metadata !"fpexcept.strict") strictfp
+  %sel = select i1 %cmp, float %x, float %y
+  ret float %sel
+}
+
+define float @pseudo_fmin_float_wrong_pred2(float %x, float %y) strictfp {
+; CHECK-LABEL: pseudo_fmin_float_wrong_pred2:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    kebr %f0, %f2
+; CHECK-NEXT:    bnher %r14
+; CHECK-NEXT:  .LBB3_1:
+; CHECK-NEXT:    ldr %f0, %f2
+; CHECK-NEXT:    br %r14
+  %cmp = call i1 @llvm.experimental.constrained.fcmps(float %x, float %y, metadata !"ult", metadata !"fpexcept.strict") strictfp
+  %sel = select i1 %cmp, float %x, float %y
+  ret float %sel
+}
+
+define double @pseudo_fmin_double(double %x, double %y) strictfp {
+; CHECK-LABEL: pseudo_fmin_double:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    wfmindb %f0, %f0, %f2, 2
+; CHECK-NEXT:    br %r14
+  %cmp = call i1 @llvm.experimental.constrained.fcmps(double %x, double %y, metadata !"olt", metadata !"fpexcept.strict") strictfp
+  %sel = select i1 %cmp, double %x, double %y
+  ret double %sel
+}
+
+define fp128 @pseudo_fmin_fp128(fp128 %x, fp128 %y) strictfp {
+; CHECK-LABEL: pseudo_fmin_fp128:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vl %v0, 0(%r4), 3
+; CHECK-NEXT:    vl %v1, 0(%r3), 3
+; CHECK-NEXT:    wfminxb %v0, %v1, %v0, 2
+; CHECK-NEXT:    vst %v0, 0(%r2), 3
+; CHECK-NEXT:    br %r14
+  %cmp = call i1 @llvm.experimental.constrained.fcmps(fp128 %x, fp128 %y, metadata !"olt", metadata !"fpexcept.strict") strictfp
+  %sel = select i1 %cmp, fp128 %x, fp128 %y
+  ret fp128 %sel
+}
+
+define half @pseudo_fmin_half(half %x, half %y) strictfp nounwind {
+; CHECK-LABEL: pseudo_fmin_half:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    stmg %r14, %r15, 112(%r15)
+; CHECK-NEXT:    aghi %r15, -192
+; CHECK-NEXT:    std %f8, 184(%r15) # 8-byte Spill
+; CHECK-NEXT:    std %f9, 176(%r15) # 8-byte Spill
+; CHECK-NEXT:    std %f10, 168(%r15) # 8-byte Spill
+; CHECK-NEXT:    std %f11, 160(%r15) # 8-byte Spill
+; CHECK-NEXT:    ldr %f8, %f0
+; CHECK-NEXT:    ldr %f0, %f2
+; CHECK-NEXT:    ldr %f9, %f2
+; CHECK-NEXT:    brasl %r14, __extendhfsf2 at PLT
+; CHECK-NEXT:    ldr %f10, %f0
+; CHECK-NEXT:    ldr %f0, %f8
+; CHECK-NEXT:    brasl %r14, __extendhfsf2 at PLT
+; CHECK-NEXT:    ldr %f11, %f0
+; CHECK-NEXT:    ldr %f0, %f8
+; CHECK-NEXT:    brasl %r14, __extendhfsf2 at PLT
+; CHECK-NEXT:    ldr %f8, %f0
+; CHECK-NEXT:    ldr %f0, %f9
+; CHECK-NEXT:    brasl %r14, __extendhfsf2 at PLT
+; CHECK-NEXT:    kebr %f11, %f10
+; CHECK-NEXT:    jl .LBB6_2
+; CHECK-NEXT:  # %bb.1:
+; CHECK-NEXT:    ldr %f8, %f0
+; CHECK-NEXT:  .LBB6_2:
+; CHECK-NEXT:    ldr %f0, %f8
+; CHECK-NEXT:    brasl %r14, __truncsfhf2 at PLT
+; CHECK-NEXT:    ld %f8, 184(%r15) # 8-byte Reload
+; CHECK-NEXT:    ld %f9, 176(%r15) # 8-byte Reload
+; CHECK-NEXT:    ld %f10, 168(%r15) # 8-byte Reload
+; CHECK-NEXT:    ld %f11, 160(%r15) # 8-byte Reload
+; CHECK-NEXT:    lmg %r14, %r15, 304(%r15)
+; CHECK-NEXT:    br %r14
+  %cmp = call i1 @llvm.experimental.constrained.fcmps(half %x, half %y, metadata !"olt", metadata !"fpexcept.strict") strictfp
+  %sel = select i1 %cmp, half %x, half %y
+  ret half %sel
+}
+
+define <4 x float> @pseudo_fmin_v4f32(<4 x float> %x, <4 x float> %y) strictfp {
+; CHECK-LABEL: pseudo_fmin_v4f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vfminsb %v24, %v24, %v26, 2
+; CHECK-NEXT:    br %r14
+  %cmp = call <4 x i1> @llvm.experimental.constrained.fcmps(<4 x float> %x, <4 x float> %y, metadata !"olt", metadata !"fpexcept.strict") strictfp
+  %sel = select <4 x i1> %cmp, <4 x float> %x, <4 x float> %y
+  ret <4 x float> %sel
+}
+
+define <2 x double> @pseudo_fmin_v2f64(<2 x double> %x, <2 x double> %y) strictfp {
+; CHECK-LABEL: pseudo_fmin_v2f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vfmindb %v24, %v24, %v26, 2
+; CHECK-NEXT:    br %r14
+  %cmp = call <2 x i1> @llvm.experimental.constrained.fcmps(<2 x double> %x, <2 x double> %y, metadata !"olt", metadata !"fpexcept.strict") strictfp
+  %sel = select <2 x i1> %cmp, <2 x double> %x, <2 x double> %y
+  ret <2 x double> %sel
+}
+
+define <4 x double> @pseudo_fmin_v4f64(<4 x double> %x, <4 x double> %y) strictfp {
+; CHECK-LABEL: pseudo_fmin_v4f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vfmindb %v24, %v24, %v28, 2
+; CHECK-NEXT:    vfmindb %v26, %v26, %v30, 2
+; CHECK-NEXT:    br %r14
+  %cmp = call <4 x i1> @llvm.experimental.constrained.fcmps(<4 x double> %x, <4 x double> %y, metadata !"olt", metadata !"fpexcept.strict") strictfp
+  %sel = select <4 x i1> %cmp, <4 x double> %x, <4 x double> %y
+  ret <4 x double> %sel
+}

``````````

</details>


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


More information about the llvm-commits mailing list