diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -16532,6 +16532,70 @@ This function follows the IEEE-754 semantics for minNum. +'``llvm.experimental.constrained.maximum``' Intrinsic +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: +""""""" + +:: + + declare + @llvm.experimental.constrained.maximum( , + metadata ) + +Overview: +""""""""" + +The '``llvm.experimental.constrained.maximum``' intrinsic returns the maximum +of the two arguments, propagating NaNs and treating -0.0 as less than +0.0. + +Arguments: +"""""""""" + +The first two arguments and the return value are floating-point numbers +of the same type. + +The third argument specifies the exception behavior as described above. + +Semantics: +"""""""""" + +This function follows semantics specified in the draft of IEEE 754-2018. + + +'``llvm.experimental.constrained.minimum``' Intrinsic +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: +""""""" + +:: + + declare + @llvm.experimental.constrained.minimum( , + metadata ) + +Overview: +""""""""" + +The '``llvm.experimental.constrained.minimum``' intrinsic returns the minimum +of the two arguments, propagating NaNs and treating -0.0 as less than +0.0. + +Arguments: +"""""""""" + +The first two arguments and the return value are floating-point numbers +of the same type. + +The third argument specifies the exception behavior as described above. + +Semantics: +"""""""""" + +This function follows semantics specified in the draft of IEEE 754-2018. + + '``llvm.experimental.constrained.ceil``' Intrinsic ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/llvm/include/llvm/CodeGen/ISDOpcodes.h b/llvm/include/llvm/CodeGen/ISDOpcodes.h --- a/llvm/include/llvm/CodeGen/ISDOpcodes.h +++ b/llvm/include/llvm/CodeGen/ISDOpcodes.h @@ -304,6 +304,7 @@ STRICT_FRINT, STRICT_FNEARBYINT, STRICT_FMAXNUM, STRICT_FMINNUM, STRICT_FCEIL, STRICT_FFLOOR, STRICT_FROUND, STRICT_FTRUNC, STRICT_LROUND, STRICT_LLROUND, STRICT_LRINT, STRICT_LLRINT, + STRICT_FMAXIMUM, STRICT_FMINIMUM, /// STRICT_FP_TO_[US]INT - Convert a floating point value to a signed or /// unsigned integer. These have the same semantics as fptosi and fptoui diff --git a/llvm/include/llvm/IR/ConstrainedOps.def b/llvm/include/llvm/IR/ConstrainedOps.def --- a/llvm/include/llvm/IR/ConstrainedOps.def +++ b/llvm/include/llvm/IR/ConstrainedOps.def @@ -70,6 +70,8 @@ FUNCTION(llround, 1, 0, experimental_constrained_llround, LLROUND) FUNCTION(maxnum, 2, 0, experimental_constrained_maxnum, FMAXNUM) FUNCTION(minnum, 2, 0, experimental_constrained_minnum, FMINNUM) +FUNCTION(maximum, 2, 0, experimental_constrained_maximum, FMAXIMUM) +FUNCTION(minimum, 2, 0, experimental_constrained_minimum, FMINIMUM) FUNCTION(nearbyint, 1, 1, experimental_constrained_nearbyint, FNEARBYINT) FUNCTION(pow, 2, 1, experimental_constrained_pow, FPOW) FUNCTION(powi, 2, 1, experimental_constrained_powi, FPOWI) diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td --- a/llvm/include/llvm/IR/Intrinsics.td +++ b/llvm/include/llvm/IR/Intrinsics.td @@ -729,6 +729,14 @@ [ LLVMMatchType<0>, LLVMMatchType<0>, llvm_metadata_ty ]>; + def int_experimental_constrained_maximum : Intrinsic<[ llvm_anyfloat_ty ], + [ LLVMMatchType<0>, + LLVMMatchType<0>, + llvm_metadata_ty ]>; + def int_experimental_constrained_minimum : Intrinsic<[ llvm_anyfloat_ty ], + [ LLVMMatchType<0>, + LLVMMatchType<0>, + llvm_metadata_ty ]>; def int_experimental_constrained_ceil : Intrinsic<[ llvm_anyfloat_ty ], [ LLVMMatchType<0>, llvm_metadata_ty ]>; diff --git a/llvm/include/llvm/Target/TargetSelectionDAG.td b/llvm/include/llvm/Target/TargetSelectionDAG.td --- a/llvm/include/llvm/Target/TargetSelectionDAG.td +++ b/llvm/include/llvm/Target/TargetSelectionDAG.td @@ -530,6 +530,12 @@ def strict_fmaxnum : SDNode<"ISD::STRICT_FMAXNUM", SDTFPBinOp, [SDNPHasChain, SDNPCommutative, SDNPAssociative]>; +def strict_fminimum : SDNode<"ISD::STRICT_FMINIMUM", + SDTFPBinOp, [SDNPHasChain, + SDNPCommutative, SDNPAssociative]>; +def strict_fmaximum : SDNode<"ISD::STRICT_FMAXIMUM", + SDTFPBinOp, [SDNPHasChain, + SDNPCommutative, SDNPAssociative]>; def strict_fpround : SDNode<"ISD::STRICT_FP_ROUND", SDTFPRoundOp, [SDNPHasChain]>; def strict_fpextend : SDNode<"ISD::STRICT_FP_EXTEND", @@ -1384,6 +1390,12 @@ def any_fminnum : PatFrags<(ops node:$lhs, node:$rhs), [(strict_fminnum node:$lhs, node:$rhs), (fminnum node:$lhs, node:$rhs)]>; +def any_fmaximum : PatFrags<(ops node:$lhs, node:$rhs), + [(strict_fmaximum node:$lhs, node:$rhs), + (fmaximum 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_fpround : PatFrags<(ops node:$src), [(strict_fpround node:$src), (fpround node:$src)]>; diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp @@ -186,7 +186,9 @@ case ISD::FMINNUM_IEEE: return "fminnum_ieee"; case ISD::FMAXNUM_IEEE: return "fmaxnum_ieee"; case ISD::FMINIMUM: return "fminimum"; + case ISD::STRICT_FMINIMUM: return "strict_fminimum"; case ISD::FMAXIMUM: return "fmaximum"; + case ISD::STRICT_FMAXIMUM: return "strict_fmaximum"; case ISD::FNEG: return "fneg"; case ISD::FSQRT: return "fsqrt"; case ISD::STRICT_FSQRT: return "strict_fsqrt"; diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp --- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp +++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp @@ -583,6 +583,8 @@ MVT::v4f32, MVT::v2f64 }) { setOperationAction(ISD::STRICT_FMAXNUM, VT, Legal); setOperationAction(ISD::STRICT_FMINNUM, VT, Legal); + setOperationAction(ISD::STRICT_FMAXIMUM, VT, Legal); + setOperationAction(ISD::STRICT_FMINIMUM, VT, Legal); } } diff --git a/llvm/lib/Target/SystemZ/SystemZInstrVector.td b/llvm/lib/Target/SystemZ/SystemZInstrVector.td --- a/llvm/lib/Target/SystemZ/SystemZInstrVector.td +++ b/llvm/lib/Target/SystemZ/SystemZInstrVector.td @@ -1175,7 +1175,7 @@ // Maximum. multiclass VectorMax { def : FPMinMax; - def : FPMinMax; + def : FPMinMax; } let Predicates = [FeatureVectorEnhancements1] in { let Uses = [FPC], mayRaiseFPException = 1 in { @@ -1201,7 +1201,7 @@ // Minimum. multiclass VectorMin { def : FPMinMax; - def : FPMinMax; + def : FPMinMax; } let Predicates = [FeatureVectorEnhancements1] in { let Uses = [FPC], mayRaiseFPException = 1 in { diff --git a/llvm/test/CodeGen/SystemZ/vec-strict-max-01.ll b/llvm/test/CodeGen/SystemZ/vec-strict-max-01.ll --- a/llvm/test/CodeGen/SystemZ/vec-strict-max-01.ll +++ b/llvm/test/CodeGen/SystemZ/vec-strict-max-01.ll @@ -4,11 +4,16 @@ declare double @llvm.experimental.constrained.maxnum.f64(double, double, metadata) declare <2 x double> @llvm.experimental.constrained.maxnum.v2f64(<2 x double>, <2 x double>, metadata) +declare double @llvm.experimental.constrained.maximum.f64(double, double, metadata) +declare <2 x double> @llvm.experimental.constrained.maximum.v2f64(<2 x double>, <2 x double>, metadata) declare float @llvm.experimental.constrained.maxnum.f32(float, float, metadata) declare <4 x float> @llvm.experimental.constrained.maxnum.v4f32(<4 x float>, <4 x float>, metadata) +declare float @llvm.experimental.constrained.maximum.f32(float, float, metadata) +declare <4 x float> @llvm.experimental.constrained.maximum.v4f32(<4 x float>, <4 x float>, metadata) declare fp128 @llvm.experimental.constrained.maxnum.f128(fp128, fp128, metadata) +declare fp128 @llvm.experimental.constrained.maximum.f128(fp128, fp128, metadata) ; Test the f64 maxnum intrinsic. define double @f1(double %dummy, double %val1, double %val2) #0 { @@ -73,4 +78,67 @@ ret void } +; Test the f64 maximum intrinsic. +define double @f11(double %dummy, double %val1, double %val2) #0 { +; CHECK-LABEL: f11: +; CHECK: wfmaxdb %f0, %f2, %f4, 1 +; CHECK: br %r14 + %ret = call double @llvm.experimental.constrained.maximum.f64( + double %val1, double %val2, + metadata !"fpexcept.strict") #0 + ret double %ret +} + +; Test the v2f64 maximum intrinsic. +define <2 x double> @f12(<2 x double> %dummy, <2 x double> %val1, + <2 x double> %val2) #0 { +; CHECK-LABEL: f12: +; CHECK: vfmaxdb %v24, %v26, %v28, 1 +; CHECK: br %r14 + %ret = call <2 x double> @llvm.experimental.constrained.maximum.v2f64( + <2 x double> %val1, <2 x double> %val2, + metadata !"fpexcept.strict") #0 + ret <2 x double> %ret +} + +; Test the f32 maximum intrinsic. +define float @f13(float %dummy, float %val1, float %val2) #0 { +; CHECK-LABEL: f13: +; CHECK: wfmaxsb %f0, %f2, %f4, 1 +; CHECK: br %r14 + %ret = call float @llvm.experimental.constrained.maximum.f32( + float %val1, float %val2, + metadata !"fpexcept.strict") #0 + ret float %ret +} + +; Test the v4f32 maximum intrinsic. +define <4 x float> @f14(<4 x float> %dummy, <4 x float> %val1, + <4 x float> %val2) #0 { +; CHECK-LABEL: f14: +; CHECK: vfmaxsb %v24, %v26, %v28, 1 +; CHECK: br %r14 + %ret = call <4 x float> @llvm.experimental.constrained.maximum.v4f32( + <4 x float> %val1, <4 x float> %val2, + metadata !"fpexcept.strict") #0 + ret <4 x float> %ret +} + +; Test the f128 maximum intrinsic. +define void @f15(fp128 *%ptr1, fp128 *%ptr2, fp128 *%dst) #0 { +; CHECK-LABEL: f15: +; CHECK-DAG: vl [[REG1:%v[0-9]+]], 0(%r2) +; CHECK-DAG: vl [[REG2:%v[0-9]+]], 0(%r3) +; CHECK: wfmaxxb [[RES:%v[0-9]+]], [[REG1]], [[REG2]], 1 +; CHECK: vst [[RES]], 0(%r4) +; CHECK: br %r14 + %val1 = load fp128, fp128* %ptr1 + %val2 = load fp128, fp128* %ptr2 + %res = call fp128 @llvm.experimental.constrained.maximum.f128( + fp128 %val1, fp128 %val2, + metadata !"fpexcept.strict") #0 + store fp128 %res, fp128* %dst + ret void +} + attributes #0 = { strictfp } diff --git a/llvm/test/CodeGen/SystemZ/vec-strict-min-01.ll b/llvm/test/CodeGen/SystemZ/vec-strict-min-01.ll --- a/llvm/test/CodeGen/SystemZ/vec-strict-min-01.ll +++ b/llvm/test/CodeGen/SystemZ/vec-strict-min-01.ll @@ -4,11 +4,16 @@ declare double @llvm.experimental.constrained.minnum.f64(double, double, metadata) declare <2 x double> @llvm.experimental.constrained.minnum.v2f64(<2 x double>, <2 x double>, metadata) +declare double @llvm.experimental.constrained.minimum.f64(double, double, metadata) +declare <2 x double> @llvm.experimental.constrained.minimum.v2f64(<2 x double>, <2 x double>, metadata) declare float @llvm.experimental.constrained.minnum.f32(float, float, metadata) declare <4 x float> @llvm.experimental.constrained.minnum.v4f32(<4 x float>, <4 x float>, metadata) +declare float @llvm.experimental.constrained.minimum.f32(float, float, metadata) +declare <4 x float> @llvm.experimental.constrained.minimum.v4f32(<4 x float>, <4 x float>, metadata) declare fp128 @llvm.experimental.constrained.minnum.f128(fp128, fp128, metadata) +declare fp128 @llvm.experimental.constrained.minimum.f128(fp128, fp128, metadata) ; Test the f64 minnum intrinsic. define double @f1(double %dummy, double %val1, double %val2) #0 { @@ -73,4 +78,67 @@ ret void } +; Test the f64 minimum intrinsic. +define double @f11(double %dummy, double %val1, double %val2) #0 { +; CHECK-LABEL: f11: +; CHECK: wfmindb %f0, %f2, %f4, 1 +; CHECK: br %r14 + %ret = call double @llvm.experimental.constrained.minimum.f64( + double %val1, double %val2, + metadata !"fpexcept.strict") #0 + ret double %ret +} + +; Test the v2f64 minimum intrinsic. +define <2 x double> @f12(<2 x double> %dummy, <2 x double> %val1, + <2 x double> %val2) #0 { +; CHECK-LABEL: f12: +; CHECK: vfmindb %v24, %v26, %v28, 1 +; CHECK: br %r14 + %ret = call <2 x double> @llvm.experimental.constrained.minimum.v2f64( + <2 x double> %val1, <2 x double> %val2, + metadata !"fpexcept.strict") #0 + ret <2 x double> %ret +} + +; Test the f32 minimum intrinsic. +define float @f13(float %dummy, float %val1, float %val2) #0 { +; CHECK-LABEL: f13: +; CHECK: wfminsb %f0, %f2, %f4, 1 +; CHECK: br %r14 + %ret = call float @llvm.experimental.constrained.minimum.f32( + float %val1, float %val2, + metadata !"fpexcept.strict") #0 + ret float %ret +} + +; Test the v4f32 minimum intrinsic. +define <4 x float> @f14(<4 x float> %dummy, <4 x float> %val1, + <4 x float> %val2) #0 { +; CHECK-LABEL: f14: +; CHECK: vfminsb %v24, %v26, %v28, 1 +; CHECK: br %r14 + %ret = call <4 x float> @llvm.experimental.constrained.minimum.v4f32( + <4 x float> %val1, <4 x float> %val2, + metadata !"fpexcept.strict") #0 + ret <4 x float> %ret +} + +; Test the f128 minimum intrinsic. +define void @f15(fp128 *%ptr1, fp128 *%ptr2, fp128 *%dst) #0 { +; CHECK-LABEL: f15: +; CHECK-DAG: vl [[REG1:%v[0-9]+]], 0(%r2) +; CHECK-DAG: vl [[REG2:%v[0-9]+]], 0(%r3) +; CHECK: wfminxb [[RES:%v[0-9]+]], [[REG1]], [[REG2]], 1 +; CHECK: vst [[RES]], 0(%r4) +; CHECK: br %r14 + %val1 = load fp128, fp128* %ptr1 + %val2 = load fp128, fp128* %ptr2 + %res = call fp128 @llvm.experimental.constrained.minimum.f128( + fp128 %val1, fp128 %val2, + metadata !"fpexcept.strict") #0 + store fp128 %res, fp128* %dst + ret void +} + attributes #0 = { strictfp }