[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