Index: llvm/include/llvm/Analysis/ValueTracking.h =================================================================== --- llvm/include/llvm/Analysis/ValueTracking.h +++ llvm/include/llvm/Analysis/ValueTracking.h @@ -272,11 +272,16 @@ return isKnownNever(fcSubnormal); } - /// Return true if it's known this can never be a negativesubnormal + /// Return true if it's known this can never be a negative subnormal bool isKnownNeverNegSubnormal() const { return isKnownNever(fcNegSubnormal); } + /// Return true if it's known this can never be a positive subnormal + bool isKnownNeverPosSubnormal() const { + return isKnownNever(fcPosSubnormal); + } + /// Return true if it's known this can never be a zero. This means a literal /// [+-]0, and does not include denormal inputs implicitly treated as [+-]0. bool isKnownNeverZero() const { @@ -288,6 +293,11 @@ return isKnownNever(fcNegZero); } + /// Return true if it's known this can never be a literal positive zero. + bool isKnownNeverPosZero() const { + return isKnownNever(fcPosZero); + } + /// Return true if it's know this can never be interpreted as a zero. This /// extends isKnownNeverZero to cover the case where the assumed /// floating-point mode for the function interprets denormals as zero. @@ -296,6 +306,9 @@ /// Return true if it's know this can never be interpreted as a negative zero. bool isKnownNeverLogicalNegZero(const Function &F, Type *Ty) const; + /// Return true if it's know this can never be interpreted as a positive zero. + bool isKnownNeverLogicalPosZero(const Function &F, Type *Ty) const; + /// Return true if we can prove that the analyzed floating-point value is /// either NaN or never less than -0.0. /// Index: llvm/lib/Analysis/ValueTracking.cpp =================================================================== --- llvm/lib/Analysis/ValueTracking.cpp +++ llvm/lib/Analysis/ValueTracking.cpp @@ -3912,6 +3912,20 @@ return F.getDenormalMode(Ty->getFltSemantics()).Input == DenormalMode::IEEE; } +static bool inputDenormalIsIEEEOrPosZero(const Function &F, const Type *Ty) { + Ty = Ty->getScalarType(); + DenormalMode Mode = F.getDenormalMode(Ty->getFltSemantics()); + return Mode.Input == DenormalMode::IEEE || + Mode.Input == DenormalMode::PositiveZero; +} + +static bool outputDenormalIsIEEEOrPosZero(const Function &F, const Type *Ty) { + Ty = Ty->getScalarType(); + DenormalMode Mode = F.getDenormalMode(Ty->getFltSemantics()); + return Mode.Output == DenormalMode::IEEE || + Mode.Output == DenormalMode::PositiveZero; +} + bool KnownFPClass::isKnownNeverLogicalZero(const Function &F, Type *Ty) const { return isKnownNeverZero() && (isKnownNeverSubnormal() || inputDenormalIsIEEE(F, Ty)); @@ -3919,7 +3933,32 @@ bool KnownFPClass::isKnownNeverLogicalNegZero(const Function &F, Type *Ty) const { return isKnownNeverNegZero() && - (isKnownNeverNegSubnormal() || inputDenormalIsIEEE(F, Ty)); + (isKnownNeverNegSubnormal() || inputDenormalIsIEEEOrPosZero(F, Ty)); +} + +bool KnownFPClass::isKnownNeverLogicalPosZero(const Function &F, + Type *Ty) const { + if (!isKnownNeverPosZero()) + return false; + + // If we know there are no denormals, nothing can be flushed to zero. + if (isKnownNeverSubnormal()) + return true; + + DenormalMode Mode = F.getDenormalMode(Ty->getScalarType()->getFltSemantics()); + switch (Mode.Input) { + case DenormalMode::IEEE: + return true; + case DenormalMode::PreserveSign: + // Negative subnormal won't flush to +0 + return isKnownNeverPosSubnormal(); + case DenormalMode::PositiveZero: + default: + // Both positive and negative subnormal could flush to +0 + return false; + } + + llvm_unreachable("covered switch over denormal mode"); } /// Returns a pair of values, which if passed to llvm.is.fpclass, returns the @@ -4252,7 +4291,8 @@ if (Depth == MaxAnalysisRecursionDepth) return; - switch (Op->getOpcode()) { + const unsigned Opc = Op->getOpcode(); + switch (Opc) { case Instruction::FNeg: { computeKnownFPClass(Op->getOperand(0), DemandedElts, InterestedClasses, Known, Depth + 1, Q, TLI); @@ -4511,16 +4551,35 @@ KnownFPClass KnownLHS, KnownRHS; computeKnownFPClass(Op->getOperand(1), DemandedElts, fcNan | fcInf, KnownRHS, Depth + 1, Q, TLI); - if (KnownRHS.isKnownNeverNaN()) { + + if (KnownRHS.isKnownNeverNaN() || KnownRHS.isKnownNeverNegZero() || + (Opc == Instruction::FSub && KnownRHS.isKnownNeverPosZero())) { // RHS is canonically cheaper to compute. Skip inspecting the LHS if // there's no point. computeKnownFPClass(Op->getOperand(0), DemandedElts, fcNan | fcInf, KnownLHS, Depth + 1, Q, TLI); // Adding positive and negative infinity produces NaN. // TODO: Check sign of infinities. - if (KnownLHS.isKnownNeverNaN() && + if (KnownLHS.isKnownNeverNaN() && KnownRHS.isKnownNeverNaN() && (KnownLHS.isKnownNeverInfinity() || KnownRHS.isKnownNeverInfinity())) Known.knownNot(fcNan); + + const Function *F = cast(Op)->getFunction(); + if (Op->getOpcode() == Instruction::FAdd) { + // (fadd x, 0.0) is guaranteed to return +0.0, not -0.0. + if ((KnownLHS.isKnownNeverLogicalNegZero(*F, Op->getType()) || + KnownRHS.isKnownNeverLogicalNegZero(*F, Op->getType())) && + // Make sure output negative denormal can't flush to -0 + outputDenormalIsIEEEOrPosZero(*F, Op->getType())) + Known.knownNot(fcNegZero); + } else { + // Only fsub -0, +0 can return -0 + if ((KnownLHS.isKnownNeverLogicalNegZero(*F, Op->getType()) || + KnownRHS.isKnownNeverLogicalPosZero(*F, Op->getType())) && + // Make sure output negative denormal can't flush to -0 + outputDenormalIsIEEEOrPosZero(*F, Op->getType())) + Known.knownNot(fcNegZero); + } } break; Index: llvm/test/Transforms/Attributor/nofpclass-sqrt.ll =================================================================== --- llvm/test/Transforms/Attributor/nofpclass-sqrt.ll +++ llvm/test/Transforms/Attributor/nofpclass-sqrt.ll @@ -151,9 +151,9 @@ } define float @ret_sqrt_dapz_noinf_nozero(float nofpclass(inf zero) %arg0) #2 { -; CHECK-LABEL: define nofpclass(inf nsub nnorm) float @ret_sqrt_dapz_noinf_nozero +; CHECK-LABEL: define nofpclass(inf nzero nsub nnorm) float @ret_sqrt_dapz_noinf_nozero ; CHECK-SAME: (float nofpclass(inf zero) [[ARG0:%.*]]) #[[ATTR4:[0-9]+]] { -; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(inf nsub nnorm) float @llvm.sqrt.f32(float [[ARG0]]) #[[ATTR10]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(inf nzero nsub nnorm) float @llvm.sqrt.f32(float [[ARG0]]) #[[ATTR10]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.sqrt.f32(float %arg0) @@ -161,9 +161,9 @@ } define float @ret_sqrt_dapz_noinf_nonegzero(float nofpclass(inf nzero) %arg0) #2 { -; CHECK-LABEL: define nofpclass(inf nsub nnorm) float @ret_sqrt_dapz_noinf_nonegzero +; CHECK-LABEL: define nofpclass(inf nzero nsub nnorm) float @ret_sqrt_dapz_noinf_nonegzero ; CHECK-SAME: (float nofpclass(inf nzero) [[ARG0:%.*]]) #[[ATTR4]] { -; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(inf nsub nnorm) float @llvm.sqrt.f32(float [[ARG0]]) #[[ATTR10]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(inf nzero nsub nnorm) float @llvm.sqrt.f32(float [[ARG0]]) #[[ATTR10]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.sqrt.f32(float %arg0) Index: llvm/test/Transforms/Attributor/nofpclass.ll =================================================================== --- llvm/test/Transforms/Attributor/nofpclass.ll +++ llvm/test/Transforms/Attributor/nofpclass.ll @@ -210,7 +210,7 @@ define void @nofpclass_call_use_after_unannotated_use(float %arg) { ; CHECK-LABEL: define void @nofpclass_call_use_after_unannotated_use ; CHECK-SAME: (float [[ARG:%.*]]) { -; CHECK-NEXT: call void @extern(float [[ARG]]) #[[ATTR6:[0-9]+]] +; CHECK-NEXT: call void @extern(float [[ARG]]) #[[ATTR12:[0-9]+]] ; CHECK-NEXT: call void @extern(float nofpclass(nan inf) [[ARG]]) ; CHECK-NEXT: ret void ; @@ -333,7 +333,7 @@ ; CHECK-SAME: (float returned nofpclass(nan) [[ARG:%.*]]) { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[IS_NOT_NAN:%.*]] = fcmp ord float [[ARG]], 0.000000e+00 -; CHECK-NEXT: call void @llvm.assume(i1 noundef [[IS_NOT_NAN]]) #[[ATTR7:[0-9]+]] +; CHECK-NEXT: call void @llvm.assume(i1 noundef [[IS_NOT_NAN]]) #[[ATTR13:[0-9]+]] ; CHECK-NEXT: call void @extern.use(float nofpclass(nan) [[ARG]]) ; CHECK-NEXT: ret float [[ARG]] ; @@ -377,13 +377,13 @@ ; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) ; TUNIT-LABEL: define float @call_noinf_0 ; TUNIT-SAME: (float nofpclass(inf) [[ARG:%.*]]) #[[ATTR2]] { -; TUNIT-NEXT: [[RESULT:%.*]] = call float @only_nofpclass_inf_callers(float nofpclass(inf) [[ARG]]) #[[ATTR8:[0-9]+]] +; TUNIT-NEXT: [[RESULT:%.*]] = call float @only_nofpclass_inf_callers(float nofpclass(inf) [[ARG]]) #[[ATTR14:[0-9]+]] ; TUNIT-NEXT: ret float [[RESULT]] ; ; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(none) ; CGSCC-LABEL: define float @call_noinf_0 ; CGSCC-SAME: (float nofpclass(inf) [[ARG:%.*]]) #[[ATTR3:[0-9]+]] { -; CGSCC-NEXT: [[RESULT:%.*]] = call float @only_nofpclass_inf_callers(float nofpclass(inf) [[ARG]]) #[[ATTR7]] +; CGSCC-NEXT: [[RESULT:%.*]] = call float @only_nofpclass_inf_callers(float nofpclass(inf) [[ARG]]) #[[ATTR13]] ; CGSCC-NEXT: ret float [[RESULT]] ; %result = call float @only_nofpclass_inf_callers(float %arg) @@ -394,13 +394,13 @@ ; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) ; TUNIT-LABEL: define float @call_noinf_1 ; TUNIT-SAME: (float [[ARG:%.*]]) #[[ATTR2]] { -; TUNIT-NEXT: [[RESULT:%.*]] = call float @only_nofpclass_inf_callers(float nofpclass(inf) [[ARG]]) #[[ATTR8]] +; TUNIT-NEXT: [[RESULT:%.*]] = call float @only_nofpclass_inf_callers(float nofpclass(inf) [[ARG]]) #[[ATTR14]] ; TUNIT-NEXT: ret float [[RESULT]] ; ; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(none) ; CGSCC-LABEL: define float @call_noinf_1 ; CGSCC-SAME: (float [[ARG:%.*]]) #[[ATTR3]] { -; CGSCC-NEXT: [[RESULT:%.*]] = call float @only_nofpclass_inf_callers(float nofpclass(inf) [[ARG]]) #[[ATTR7]] +; CGSCC-NEXT: [[RESULT:%.*]] = call float @only_nofpclass_inf_callers(float nofpclass(inf) [[ARG]]) #[[ATTR13]] ; CGSCC-NEXT: ret float [[RESULT]] ; %result = call float @only_nofpclass_inf_callers(float nofpclass(inf) %arg) @@ -423,13 +423,13 @@ ; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) ; TUNIT-LABEL: define nofpclass(inf) float @call_noinf_return_0 ; TUNIT-SAME: (float [[ARG:%.*]]) #[[ATTR2]] { -; TUNIT-NEXT: [[RESULT:%.*]] = call nofpclass(inf) float @only_nofpclass_inf_return_users(float [[ARG]]) #[[ATTR8]] +; TUNIT-NEXT: [[RESULT:%.*]] = call nofpclass(inf) float @only_nofpclass_inf_return_users(float [[ARG]]) #[[ATTR14]] ; TUNIT-NEXT: ret float [[RESULT]] ; ; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(none) ; CGSCC-LABEL: define nofpclass(inf) float @call_noinf_return_0 ; CGSCC-SAME: (float [[ARG:%.*]]) #[[ATTR3]] { -; CGSCC-NEXT: [[RESULT:%.*]] = call nofpclass(inf) float @only_nofpclass_inf_return_users(float [[ARG]]) #[[ATTR7]] +; CGSCC-NEXT: [[RESULT:%.*]] = call nofpclass(inf) float @only_nofpclass_inf_return_users(float [[ARG]]) #[[ATTR13]] ; CGSCC-NEXT: ret float [[RESULT]] ; %result = call nofpclass(inf) float @only_nofpclass_inf_return_users(float %arg) @@ -440,13 +440,13 @@ ; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) ; TUNIT-LABEL: define nofpclass(inf) float @call_noinf_return_1 ; TUNIT-SAME: (float [[ARG:%.*]]) #[[ATTR2]] { -; TUNIT-NEXT: [[RESULT:%.*]] = call nofpclass(inf) float @only_nofpclass_inf_return_users(float [[ARG]]) #[[ATTR8]] +; TUNIT-NEXT: [[RESULT:%.*]] = call nofpclass(inf) float @only_nofpclass_inf_return_users(float [[ARG]]) #[[ATTR14]] ; TUNIT-NEXT: ret float [[RESULT]] ; ; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(none) ; CGSCC-LABEL: define nofpclass(inf) float @call_noinf_return_1 ; CGSCC-SAME: (float [[ARG:%.*]]) #[[ATTR3]] { -; CGSCC-NEXT: [[RESULT:%.*]] = call nofpclass(inf) float @only_nofpclass_inf_return_users(float [[ARG]]) #[[ATTR7]] +; CGSCC-NEXT: [[RESULT:%.*]] = call nofpclass(inf) float @only_nofpclass_inf_return_users(float [[ARG]]) #[[ATTR13]] ; CGSCC-NEXT: ret float [[RESULT]] ; %result = call nofpclass(inf) float @only_nofpclass_inf_return_users(float %arg) @@ -458,7 +458,7 @@ ; CHECK-SAME: (float returned nofpclass(nan zero) [[ARG:%.*]]) { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[IS_NOT_ZERO_OR_NAN:%.*]] = fcmp one float [[ARG]], 0.000000e+00 -; CHECK-NEXT: call void @llvm.assume(i1 noundef [[IS_NOT_ZERO_OR_NAN]]) #[[ATTR7]] +; CHECK-NEXT: call void @llvm.assume(i1 noundef [[IS_NOT_ZERO_OR_NAN]]) #[[ATTR13]] ; CHECK-NEXT: call void @extern.use(float nofpclass(nan zero) [[ARG]]) ; CHECK-NEXT: ret float [[ARG]] ; @@ -474,7 +474,7 @@ ; CHECK-SAME: (float returned nofpclass(zero) [[ARG:%.*]]) { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[IS_NOT_ZERO_OR_NAN:%.*]] = fcmp une float [[ARG]], 0.000000e+00 -; CHECK-NEXT: call void @llvm.assume(i1 noundef [[IS_NOT_ZERO_OR_NAN]]) #[[ATTR7]] +; CHECK-NEXT: call void @llvm.assume(i1 noundef [[IS_NOT_ZERO_OR_NAN]]) #[[ATTR13]] ; CHECK-NEXT: call void @extern.use(float nofpclass(zero) [[ARG]]) ; CHECK-NEXT: ret float [[ARG]] ; @@ -489,9 +489,9 @@ ; CHECK-LABEL: define nofpclass(nan inf norm) half @fcmp_assume_issubnormal_callsite_arg_return ; CHECK-SAME: (half returned nofpclass(nan inf norm) [[ARG:%.*]]) { ; CHECK-NEXT: entry: -; CHECK-NEXT: [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) half @llvm.fabs.f16(half nofpclass(nan inf norm) [[ARG]]) #[[ATTR7]] +; CHECK-NEXT: [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) half @llvm.fabs.f16(half nofpclass(nan inf norm) [[ARG]]) #[[ATTR13]] ; CHECK-NEXT: [[IS_SUBNORMAL:%.*]] = fcmp olt half [[FABS]], 0xH0400 -; CHECK-NEXT: call void @llvm.assume(i1 noundef [[IS_SUBNORMAL]]) #[[ATTR7]] +; CHECK-NEXT: call void @llvm.assume(i1 noundef [[IS_SUBNORMAL]]) #[[ATTR13]] ; CHECK-NEXT: call void @extern.use.f16(half nofpclass(nan inf norm) [[ARG]]) ; CHECK-NEXT: ret half [[ARG]] ; @@ -525,11 +525,11 @@ ; CHECK-LABEL: define nofpclass(nan ninf zero sub norm) half @fcmp_assume2_callsite_arg_return ; CHECK-SAME: (half returned nofpclass(nan ninf zero sub norm) [[ARG:%.*]]) { ; CHECK-NEXT: entry: -; CHECK-NEXT: [[FABS:%.*]] = call nofpclass(nan ninf zero sub norm) half @llvm.fabs.f16(half nofpclass(nan ninf zero sub norm) [[ARG]]) #[[ATTR7]] +; CHECK-NEXT: [[FABS:%.*]] = call nofpclass(nan ninf zero sub norm) half @llvm.fabs.f16(half nofpclass(nan ninf zero sub norm) [[ARG]]) #[[ATTR13]] ; CHECK-NEXT: [[NOT_SUBNORMAL_OR_ZERO:%.*]] = fcmp oge half [[FABS]], 0xH0400 -; CHECK-NEXT: call void @llvm.assume(i1 noundef [[NOT_SUBNORMAL_OR_ZERO]]) #[[ATTR7]] +; CHECK-NEXT: call void @llvm.assume(i1 noundef [[NOT_SUBNORMAL_OR_ZERO]]) #[[ATTR13]] ; CHECK-NEXT: [[NOT_INF:%.*]] = fcmp oeq half [[ARG]], 0xH7C00 -; CHECK-NEXT: call void @llvm.assume(i1 noundef [[NOT_INF]]) #[[ATTR7]] +; CHECK-NEXT: call void @llvm.assume(i1 noundef [[NOT_INF]]) #[[ATTR13]] ; CHECK-NEXT: call void @extern.use.f16(half nofpclass(nan ninf zero sub norm) [[ARG]]) ; CHECK-NEXT: ret half [[ARG]] ; @@ -549,8 +549,8 @@ ; CHECK-LABEL: define nofpclass(nan pinf pzero sub nnorm) float @is_fpclass_assume_arg_return ; CHECK-SAME: (float returned nofpclass(nan pinf pzero sub nnorm) [[ARG:%.*]]) { ; CHECK-NEXT: entry: -; CHECK-NEXT: [[CLASS_TEST:%.*]] = call i1 @llvm.is.fpclass.f32(float nofpclass(nan pinf pzero sub nnorm) [[ARG]], i32 noundef 292) #[[ATTR7]] -; CHECK-NEXT: call void @llvm.assume(i1 noundef [[CLASS_TEST]]) #[[ATTR7]] +; CHECK-NEXT: [[CLASS_TEST:%.*]] = call i1 @llvm.is.fpclass.f32(float nofpclass(nan pinf pzero sub nnorm) [[ARG]], i32 noundef 292) #[[ATTR13]] +; CHECK-NEXT: call void @llvm.assume(i1 noundef [[CLASS_TEST]]) #[[ATTR13]] ; CHECK-NEXT: call void @extern.use(float nofpclass(nan pinf pzero sub nnorm) [[ARG]]) ; CHECK-NEXT: ret float [[ARG]] ; @@ -567,11 +567,11 @@ ; CHECK-LABEL: define nofpclass(nan inf norm) half @assume_fcmp_fabs_with_other_fabs_assume ; CHECK-SAME: (half returned nofpclass(nan inf norm) [[ARG:%.*]]) { ; CHECK-NEXT: entry: -; CHECK-NEXT: [[FABS:%.*]] = call nofpclass(nan inf zero nsub norm) half @llvm.fabs.f16(half nofpclass(nan inf norm) [[ARG]]) #[[ATTR7]] +; CHECK-NEXT: [[FABS:%.*]] = call nofpclass(nan inf zero nsub norm) half @llvm.fabs.f16(half nofpclass(nan inf norm) [[ARG]]) #[[ATTR13]] ; CHECK-NEXT: [[UNRELATED_FABS:%.*]] = fcmp one half [[FABS]], 0xH0000 -; CHECK-NEXT: call void @llvm.assume(i1 noundef [[UNRELATED_FABS]]) #[[ATTR7]] +; CHECK-NEXT: call void @llvm.assume(i1 noundef [[UNRELATED_FABS]]) #[[ATTR13]] ; CHECK-NEXT: [[IS_SUBNORMAL:%.*]] = fcmp olt half [[FABS]], 0xH0400 -; CHECK-NEXT: call void @llvm.assume(i1 noundef [[IS_SUBNORMAL]]) #[[ATTR7]] +; CHECK-NEXT: call void @llvm.assume(i1 noundef [[IS_SUBNORMAL]]) #[[ATTR13]] ; CHECK-NEXT: call void @extern.use.f16(half nofpclass(nan inf norm) [[ARG]]) ; CHECK-NEXT: call void @extern.use.f16(half nofpclass(nan inf zero nsub norm) [[FABS]]) ; CHECK-NEXT: ret half [[ARG]] @@ -594,13 +594,13 @@ ; CHECK-LABEL: define nofpclass(all) half @assume_fcmp_fabs_with_other_fabs_assume_fallback ; CHECK-SAME: (half returned nofpclass(all) [[ARG:%.*]]) { ; CHECK-NEXT: entry: -; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half nofpclass(all) [[ARG]]) #[[ATTR7]] +; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half nofpclass(all) [[ARG]]) #[[ATTR13]] ; CHECK-NEXT: [[ONE_INF:%.*]] = fcmp oeq half [[ARG]], 0xH7C00 -; CHECK-NEXT: call void @llvm.assume(i1 noundef [[ONE_INF]]) #[[ATTR7]] +; CHECK-NEXT: call void @llvm.assume(i1 noundef [[ONE_INF]]) #[[ATTR13]] ; CHECK-NEXT: [[UNRELATED_FABS:%.*]] = fcmp oeq half [[FABS]], 0xH0000 -; CHECK-NEXT: call void @llvm.assume(i1 noundef [[UNRELATED_FABS]]) #[[ATTR7]] +; CHECK-NEXT: call void @llvm.assume(i1 noundef [[UNRELATED_FABS]]) #[[ATTR13]] ; CHECK-NEXT: [[IS_SUBNORMAL:%.*]] = fcmp olt half [[FABS]], 0xH0400 -; CHECK-NEXT: call void @llvm.assume(i1 noundef [[IS_SUBNORMAL]]) #[[ATTR7]] +; CHECK-NEXT: call void @llvm.assume(i1 noundef [[IS_SUBNORMAL]]) #[[ATTR13]] ; CHECK-NEXT: call void @extern.use.f16(half nofpclass(all) [[ARG]]) ; CHECK-NEXT: call void @extern.use.f16(half nofpclass(all) [[FABS]]) ; CHECK-NEXT: ret half [[ARG]] @@ -628,7 +628,7 @@ ; CHECK-NEXT: entry: ; CHECK-NEXT: br i1 [[C]], label [[A:%.*]], label [[B:%.*]] ; CHECK: A: -; CHECK-NEXT: call void @llvm.assume(i1 noundef true) #[[ATTR7]] [ "nofpclass"(float [[RET]], i32 3) ] +; CHECK-NEXT: call void @llvm.assume(i1 noundef true) #[[ATTR13]] [ "nofpclass"(float [[RET]], i32 3) ] ; CHECK-NEXT: call void @extern.use(float nofpclass(nan) [[RET]]) ; CHECK-NEXT: ret float [[RET]] ; CHECK: B: @@ -667,7 +667,7 @@ ; TUNIT-SAME: (float nofpclass(inf) [[ARG:%.*]]) #[[ATTR2]] { ; TUNIT-NEXT: [[ALLOCA:%.*]] = alloca float, align 4 ; TUNIT-NEXT: store float [[ARG]], ptr [[ALLOCA]], align 4 -; TUNIT-NEXT: [[RET:%.*]] = call float @returned_load(ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[ALLOCA]]) #[[ATTR8]] +; TUNIT-NEXT: [[RET:%.*]] = call float @returned_load(ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[ALLOCA]]) #[[ATTR14]] ; TUNIT-NEXT: ret float [[RET]] ; ; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(none) @@ -675,7 +675,7 @@ ; CGSCC-SAME: (float nofpclass(inf) [[ARG:%.*]]) #[[ATTR3]] { ; CGSCC-NEXT: [[ALLOCA:%.*]] = alloca float, align 4 ; CGSCC-NEXT: store float [[ARG]], ptr [[ALLOCA]], align 4 -; CGSCC-NEXT: [[RET:%.*]] = call float @returned_load(ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[ALLOCA]]) #[[ATTR7]] +; CGSCC-NEXT: [[RET:%.*]] = call float @returned_load(ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[ALLOCA]]) #[[ATTR13]] ; CGSCC-NEXT: ret float [[RET]] ; %alloca = alloca float @@ -688,7 +688,7 @@ ; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @returned_fabs ; CHECK-SAME: (float [[X:%.*]]) #[[ATTR2]] { -; CHECK-NEXT: [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float [[X]]) #[[ATTR7]] +; CHECK-NEXT: [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float [[X]]) #[[ATTR13]] ; CHECK-NEXT: ret float [[FABS]] ; %fabs = call float @llvm.fabs.f32(float %x) @@ -699,7 +699,7 @@ ; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: define nofpclass(snan ninf nzero nsub nnorm) float @returned_fabs_nosnan ; CHECK-SAME: (float nofpclass(snan) [[X:%.*]]) #[[ATTR2]] { -; CHECK-NEXT: [[FABS:%.*]] = call nofpclass(snan ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(snan) [[X]]) #[[ATTR7]] +; CHECK-NEXT: [[FABS:%.*]] = call nofpclass(snan ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(snan) [[X]]) #[[ATTR13]] ; CHECK-NEXT: ret float [[FABS]] ; %fabs = call float @llvm.fabs.f32(float %x) @@ -710,7 +710,7 @@ ; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: define nofpclass(qnan ninf nzero nsub nnorm) float @returned_fabs_noqnan ; CHECK-SAME: (float nofpclass(qnan) [[X:%.*]]) #[[ATTR2]] { -; CHECK-NEXT: [[FABS:%.*]] = call nofpclass(qnan ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(qnan) [[X]]) #[[ATTR7]] +; CHECK-NEXT: [[FABS:%.*]] = call nofpclass(qnan ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(qnan) [[X]]) #[[ATTR13]] ; CHECK-NEXT: ret float [[FABS]] ; %fabs = call float @llvm.fabs.f32(float %x) @@ -721,7 +721,7 @@ ; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: define nofpclass(nan ninf nzero nsub nnorm) float @returned_fabs_nonan ; CHECK-SAME: (float nofpclass(nan) [[X:%.*]]) #[[ATTR2]] { -; CHECK-NEXT: [[FABS:%.*]] = call nofpclass(nan ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(nan) [[X]]) #[[ATTR7]] +; CHECK-NEXT: [[FABS:%.*]] = call nofpclass(nan ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(nan) [[X]]) #[[ATTR13]] ; CHECK-NEXT: ret float [[FABS]] ; %fabs = call float @llvm.fabs.f32(float %x) @@ -732,7 +732,7 @@ ; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: define nofpclass(inf nzero nsub nnorm) float @returned_fabs_noinf ; CHECK-SAME: (float nofpclass(inf) [[X:%.*]]) #[[ATTR2]] { -; CHECK-NEXT: [[FABS:%.*]] = call nofpclass(inf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(inf) [[X]]) #[[ATTR7]] +; CHECK-NEXT: [[FABS:%.*]] = call nofpclass(inf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(inf) [[X]]) #[[ATTR13]] ; CHECK-NEXT: ret float [[FABS]] ; %fabs = call float @llvm.fabs.f32(float %x) @@ -875,7 +875,7 @@ ; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @returned_fneg_fabs ; CHECK-SAME: (float [[X:%.*]]) #[[ATTR2]] { -; CHECK-NEXT: [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float [[X]]) #[[ATTR7]] +; CHECK-NEXT: [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float [[X]]) #[[ATTR13]] ; CHECK-NEXT: [[FNEG_FABS:%.*]] = fneg float [[FABS]] ; CHECK-NEXT: ret float [[FNEG_FABS]] ; @@ -888,7 +888,7 @@ ; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: define nofpclass(snan pinf pzero psub pnorm) float @returned_fneg_fabs_nosnan ; CHECK-SAME: (float nofpclass(snan) [[X:%.*]]) #[[ATTR2]] { -; CHECK-NEXT: [[FABS:%.*]] = call nofpclass(snan ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(snan) [[X]]) #[[ATTR7]] +; CHECK-NEXT: [[FABS:%.*]] = call nofpclass(snan ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(snan) [[X]]) #[[ATTR13]] ; CHECK-NEXT: [[FNEG_FABS:%.*]] = fneg float [[FABS]] ; CHECK-NEXT: ret float [[FNEG_FABS]] ; @@ -901,7 +901,7 @@ ; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: define nofpclass(qnan pinf pzero psub pnorm) float @returned_fneg_fabs_noqnan ; CHECK-SAME: (float nofpclass(qnan) [[X:%.*]]) #[[ATTR2]] { -; CHECK-NEXT: [[FABS:%.*]] = call nofpclass(qnan ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(qnan) [[X]]) #[[ATTR7]] +; CHECK-NEXT: [[FABS:%.*]] = call nofpclass(qnan ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(qnan) [[X]]) #[[ATTR13]] ; CHECK-NEXT: [[FNEG_FABS:%.*]] = fneg float [[FABS]] ; CHECK-NEXT: ret float [[FNEG_FABS]] ; @@ -914,7 +914,7 @@ ; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: define nofpclass(nan pinf pzero psub pnorm) float @returned_fneg_fabs_nonan ; CHECK-SAME: (float nofpclass(nan) [[X:%.*]]) #[[ATTR2]] { -; CHECK-NEXT: [[FABS:%.*]] = call nofpclass(nan ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(nan) [[X]]) #[[ATTR7]] +; CHECK-NEXT: [[FABS:%.*]] = call nofpclass(nan ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(nan) [[X]]) #[[ATTR13]] ; CHECK-NEXT: [[FNEG_FABS:%.*]] = fneg float [[FABS]] ; CHECK-NEXT: ret float [[FNEG_FABS]] ; @@ -927,7 +927,7 @@ ; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @returned_fneg_fabs_noneg ; CHECK-SAME: (float nofpclass(ninf nzero nsub nnorm) [[X:%.*]]) #[[ATTR2]] { -; CHECK-NEXT: [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(ninf nzero nsub nnorm) [[X]]) #[[ATTR7]] +; CHECK-NEXT: [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(ninf nzero nsub nnorm) [[X]]) #[[ATTR13]] ; CHECK-NEXT: [[FNEG_FABS:%.*]] = fneg float [[FABS]] ; CHECK-NEXT: ret float [[FNEG_FABS]] ; @@ -940,7 +940,7 @@ ; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: define nofpclass(inf zero sub norm) float @returned_fneg_fabs_nopos ; CHECK-SAME: (float nofpclass(pinf pzero psub pnorm) [[X:%.*]]) #[[ATTR2]] { -; CHECK-NEXT: [[FABS:%.*]] = call nofpclass(inf zero sub norm) float @llvm.fabs.f32(float nofpclass(pinf pzero psub pnorm) [[X]]) #[[ATTR7]] +; CHECK-NEXT: [[FABS:%.*]] = call nofpclass(inf zero sub norm) float @llvm.fabs.f32(float nofpclass(pinf pzero psub pnorm) [[X]]) #[[ATTR13]] ; CHECK-NEXT: [[FNEG_FABS:%.*]] = fneg float [[FABS]] ; CHECK-NEXT: ret float [[FNEG_FABS]] ; @@ -953,7 +953,7 @@ ; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: define nofpclass(qnan pinf pzero sub pnorm) float @returned_fneg_fabs_mixed ; CHECK-SAME: (float nofpclass(qnan ninf nzero psub nnorm) [[X:%.*]]) #[[ATTR2]] { -; CHECK-NEXT: [[FABS:%.*]] = call nofpclass(qnan ninf nzero sub nnorm) float @llvm.fabs.f32(float nofpclass(qnan ninf nzero psub nnorm) [[X]]) #[[ATTR7]] +; CHECK-NEXT: [[FABS:%.*]] = call nofpclass(qnan ninf nzero sub nnorm) float @llvm.fabs.f32(float nofpclass(qnan ninf nzero psub nnorm) [[X]]) #[[ATTR13]] ; CHECK-NEXT: [[FNEG_FABS:%.*]] = fneg float [[FABS]] ; CHECK-NEXT: ret float [[FNEG_FABS]] ; @@ -966,7 +966,7 @@ ; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: define nofpclass(inf pzero psub pnorm) float @returned_fneg_fabs_ninf_flag_fabs ; CHECK-SAME: (float [[X:%.*]]) #[[ATTR2]] { -; CHECK-NEXT: [[FABS:%.*]] = call ninf nofpclass(inf nzero nsub nnorm) float @llvm.fabs.f32(float [[X]]) #[[ATTR7]] +; CHECK-NEXT: [[FABS:%.*]] = call ninf nofpclass(inf nzero nsub nnorm) float @llvm.fabs.f32(float [[X]]) #[[ATTR13]] ; CHECK-NEXT: [[FNEG_FABS:%.*]] = fneg float [[FABS]] ; CHECK-NEXT: ret float [[FNEG_FABS]] ; @@ -979,7 +979,7 @@ ; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: define nofpclass(inf pzero psub pnorm) float @returned_fneg_fabs_ninf_flag_fneg ; CHECK-SAME: (float [[X:%.*]]) #[[ATTR2]] { -; CHECK-NEXT: [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float [[X]]) #[[ATTR7]] +; CHECK-NEXT: [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float [[X]]) #[[ATTR13]] ; CHECK-NEXT: [[FNEG_FABS:%.*]] = fneg ninf float [[FABS]] ; CHECK-NEXT: ret float [[FNEG_FABS]] ; @@ -1081,9 +1081,9 @@ ; CHECK-SAME: (float returned nofpclass(nan zero) [[ARG:%.*]]) { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[IS_NOT_ZERO_OR_NAN:%.*]] = fcmp une float [[ARG]], 0.000000e+00 -; CHECK-NEXT: call void @llvm.assume(i1 noundef [[IS_NOT_ZERO_OR_NAN]]) #[[ATTR7]] +; CHECK-NEXT: call void @llvm.assume(i1 noundef [[IS_NOT_ZERO_OR_NAN]]) #[[ATTR13]] ; CHECK-NEXT: [[IS_ORD:%.*]] = fcmp ord float [[ARG]], 0.000000e+00 -; CHECK-NEXT: call void @llvm.assume(i1 noundef [[IS_ORD]]) #[[ATTR7]] +; CHECK-NEXT: call void @llvm.assume(i1 noundef [[IS_ORD]]) #[[ATTR13]] ; CHECK-NEXT: call void @extern.use(float nofpclass(nan zero) [[ARG]]) ; CHECK-NEXT: ret float [[ARG]] ; @@ -1100,10 +1100,10 @@ ; CHECK-LABEL: define nofpclass(nan inf zero sub nnorm) float @assume_intersection_class ; CHECK-SAME: (float returned nofpclass(nan inf zero sub nnorm) [[ARG:%.*]]) { ; CHECK-NEXT: entry: -; CHECK-NEXT: [[POS_NORMAL_OR_POS_SUBNORMAL:%.*]] = call i1 @llvm.is.fpclass.f32(float nofpclass(nan inf zero sub nnorm) [[ARG]], i32 noundef 384) #[[ATTR7]] -; CHECK-NEXT: call void @llvm.assume(i1 noundef [[POS_NORMAL_OR_POS_SUBNORMAL]]) #[[ATTR7]] -; CHECK-NEXT: [[IS_NORMAL:%.*]] = call i1 @llvm.is.fpclass.f32(float nofpclass(nan inf zero sub nnorm) [[ARG]], i32 noundef 264) #[[ATTR7]] -; CHECK-NEXT: call void @llvm.assume(i1 noundef [[IS_NORMAL]]) #[[ATTR7]] +; CHECK-NEXT: [[POS_NORMAL_OR_POS_SUBNORMAL:%.*]] = call i1 @llvm.is.fpclass.f32(float nofpclass(nan inf zero sub nnorm) [[ARG]], i32 noundef 384) #[[ATTR13]] +; CHECK-NEXT: call void @llvm.assume(i1 noundef [[POS_NORMAL_OR_POS_SUBNORMAL]]) #[[ATTR13]] +; CHECK-NEXT: [[IS_NORMAL:%.*]] = call i1 @llvm.is.fpclass.f32(float nofpclass(nan inf zero sub nnorm) [[ARG]], i32 noundef 264) #[[ATTR13]] +; CHECK-NEXT: call void @llvm.assume(i1 noundef [[IS_NORMAL]]) #[[ATTR13]] ; CHECK-NEXT: call void @extern.use(float nofpclass(nan inf zero sub nnorm) [[ARG]]) ; CHECK-NEXT: ret float [[ARG]] ; @@ -1121,10 +1121,10 @@ ; CHECK-LABEL: define nofpclass(all) float @assume_intersection_none ; CHECK-SAME: (float returned nofpclass(all) [[ARG:%.*]]) { ; CHECK-NEXT: entry: -; CHECK-NEXT: [[CLASS1:%.*]] = call i1 @llvm.is.fpclass.f32(float nofpclass(all) [[ARG]], i32 noundef 682) #[[ATTR7]] -; CHECK-NEXT: call void @llvm.assume(i1 noundef [[CLASS1]]) #[[ATTR7]] -; CHECK-NEXT: [[CLASS2:%.*]] = call i1 @llvm.is.fpclass.f32(float nofpclass(all) [[ARG]], i32 noundef 341) #[[ATTR7]] -; CHECK-NEXT: call void @llvm.assume(i1 noundef [[CLASS2]]) #[[ATTR7]] +; CHECK-NEXT: [[CLASS1:%.*]] = call i1 @llvm.is.fpclass.f32(float nofpclass(all) [[ARG]], i32 noundef 682) #[[ATTR13]] +; CHECK-NEXT: call void @llvm.assume(i1 noundef [[CLASS1]]) #[[ATTR13]] +; CHECK-NEXT: [[CLASS2:%.*]] = call i1 @llvm.is.fpclass.f32(float nofpclass(all) [[ARG]], i32 noundef 341) #[[ATTR13]] +; CHECK-NEXT: call void @llvm.assume(i1 noundef [[CLASS2]]) #[[ATTR13]] ; CHECK-NEXT: call void @extern.use(float nofpclass(all) [[ARG]]) ; CHECK-NEXT: ret float [[ARG]] ; @@ -1495,7 +1495,7 @@ ; CHECK: Function Attrs: nofree norecurse nosync nounwind strictfp willreturn memory(inaccessiblemem: readwrite) ; CHECK-LABEL: define nofpclass(nan nzero sub) float @constrained_sitofp ; CHECK-SAME: (i32 [[ARG:%.*]]) #[[ATTR5:[0-9]+]] { -; CHECK-NEXT: [[VAL:%.*]] = call nofpclass(nan nzero sub) float @llvm.experimental.constrained.sitofp.f32.i32(i32 [[ARG]], metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR7]] +; CHECK-NEXT: [[VAL:%.*]] = call nofpclass(nan nzero sub) float @llvm.experimental.constrained.sitofp.f32.i32(i32 [[ARG]], metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR13]] ; CHECK-NEXT: ret float [[VAL]] ; %val = call float @llvm.experimental.constrained.sitofp.f32.i32(i32 %arg, metadata !"round.dynamic", metadata !"fpexcept.strict") @@ -1506,9 +1506,467 @@ ; CHECK: Function Attrs: nofree norecurse nosync nounwind strictfp willreturn memory(inaccessiblemem: readwrite) ; CHECK-LABEL: define nofpclass(nan ninf nzero sub nnorm) float @constrained_uitofp ; CHECK-SAME: (i32 [[ARG:%.*]]) #[[ATTR5]] { -; CHECK-NEXT: [[VAL:%.*]] = call nofpclass(nan ninf nzero sub nnorm) float @llvm.experimental.constrained.uitofp.f32.i32(i32 [[ARG]], metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR7]] +; CHECK-NEXT: [[VAL:%.*]] = call nofpclass(nan ninf nzero sub nnorm) float @llvm.experimental.constrained.uitofp.f32.i32(i32 [[ARG]], metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR13]] ; CHECK-NEXT: ret float [[VAL]] ; %val = call float @llvm.experimental.constrained.uitofp.f32.i32(i32 %arg, metadata !"round.dynamic", metadata !"fpexcept.strict") ret float %val } + +define float @fadd_p0(float %arg0) { +; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define nofpclass(nzero) float @fadd_p0 +; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR2]] { +; CHECK-NEXT: [[ADD:%.*]] = fadd float [[ARG0]], 0.000000e+00 +; CHECK-NEXT: ret float [[ADD]] +; + %add = fadd float %arg0, 0.0 + ret float %add +} + +define float @fadd_n0(float %arg0) { +; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define float @fadd_n0 +; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR2]] { +; CHECK-NEXT: [[ADD:%.*]] = fadd float [[ARG0]], -0.000000e+00 +; CHECK-NEXT: ret float [[ADD]] +; + %add = fadd float %arg0, -0.0 + ret float %add +} + +define float @fsub_p0(float %arg0) { +; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define float @fsub_p0 +; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR2]] { +; CHECK-NEXT: [[SUB:%.*]] = fsub float [[ARG0]], 0.000000e+00 +; CHECK-NEXT: ret float [[SUB]] +; + %sub = fsub float %arg0, 0.0 + ret float %sub +} + +define float @fsub_n0(float %arg0) { +; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define nofpclass(nzero) float @fsub_n0 +; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR2]] { +; CHECK-NEXT: [[SUB:%.*]] = fsub float [[ARG0]], -0.000000e+00 +; CHECK-NEXT: ret float [[SUB]] +; + %sub = fsub float %arg0, -0.0 + ret float %sub +} + +define float @fsub_p0_commute(float %arg0) { +; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define float @fsub_p0_commute +; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR2]] { +; CHECK-NEXT: [[SUB:%.*]] = fsub float 0.000000e+00, [[ARG0]] +; CHECK-NEXT: ret float [[SUB]] +; + %sub = fsub float 0.0, %arg0 + ret float %sub +} + +define float @fsub_n0_commute(float %arg0) { +; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define float @fsub_n0_commute +; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR2]] { +; CHECK-NEXT: [[SUB:%.*]] = fsub float -0.000000e+00, [[ARG0]] +; CHECK-NEXT: ret float [[SUB]] +; + %sub = fsub float -0.0, %arg0 + ret float %sub +} + +define float @fadd_p0_ftz_daz(float %arg0) #3 { +; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define nofpclass(nzero) float @fadd_p0_ftz_daz +; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR6:[0-9]+]] { +; CHECK-NEXT: [[ADD:%.*]] = fadd float [[ARG0]], 0.000000e+00 +; CHECK-NEXT: ret float [[ADD]] +; + %add = fadd float %arg0, 0.0 + ret float %add +} + +define float @fadd_n0_ftz_daz(float %arg0) #0 { +; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define float @fadd_n0_ftz_daz +; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR7:[0-9]+]] { +; CHECK-NEXT: [[ADD:%.*]] = fadd float [[ARG0]], -0.000000e+00 +; CHECK-NEXT: ret float [[ADD]] +; + %add = fadd float %arg0, -0.0 + ret float %add +} + +define float @fsub_p0_ftz_daz(float %arg0) #0 { +; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define float @fsub_p0_ftz_daz +; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR7]] { +; CHECK-NEXT: [[SUB:%.*]] = fsub float [[ARG0]], 0.000000e+00 +; CHECK-NEXT: ret float [[SUB]] +; + %sub = fsub float %arg0, 0.0 + ret float %sub +} + +define float @fsub_n0_ftz_daz(float %arg0) #0 { +; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define float @fsub_n0_ftz_daz +; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR7]] { +; CHECK-NEXT: [[SUB:%.*]] = fsub float [[ARG0]], -0.000000e+00 +; CHECK-NEXT: ret float [[SUB]] +; + %sub = fsub float %arg0, -0.0 + ret float %sub +} + +define float @fsub_p0_commute_ftz_daz(float %arg0) #0 { +; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define float @fsub_p0_commute_ftz_daz +; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR7]] { +; CHECK-NEXT: [[SUB:%.*]] = fsub float 0.000000e+00, [[ARG0]] +; CHECK-NEXT: ret float [[SUB]] +; + %sub = fsub float 0.0, %arg0 + ret float %sub +} + +define float @fsub_n0_commute_ftz_daz(float %arg0) #0 { +; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define float @fsub_n0_commute_ftz_daz +; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR7]] { +; CHECK-NEXT: [[SUB:%.*]] = fsub float -0.000000e+00, [[ARG0]] +; CHECK-NEXT: ret float [[SUB]] +; + %sub = fsub float -0.0, %arg0 + ret float %sub +} + +define float @fadd_p0_ieee_daz(float %arg0) #2 { +; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define nofpclass(nzero) float @fadd_p0_ieee_daz +; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR8:[0-9]+]] { +; CHECK-NEXT: [[ADD:%.*]] = fadd float [[ARG0]], 0.000000e+00 +; CHECK-NEXT: ret float [[ADD]] +; + %add = fadd float %arg0, 0.0 + ret float %add +} + +define float @fadd_p0_dapz_ieee(float %arg0) #4 { +; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define nofpclass(nzero) float @fadd_p0_dapz_ieee +; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR9:[0-9]+]] { +; CHECK-NEXT: [[ADD:%.*]] = fadd float [[ARG0]], 0.000000e+00 +; CHECK-NEXT: ret float [[ADD]] +; + %add = fadd float %arg0, 0.0 + ret float %add +} + +define float @fadd_n0_ieee_daz(float %arg0) #2 { +; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define float @fadd_n0_ieee_daz +; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR8]] { +; CHECK-NEXT: [[ADD:%.*]] = fadd float [[ARG0]], -0.000000e+00 +; CHECK-NEXT: ret float [[ADD]] +; + %add = fadd float %arg0, -0.0 + ret float %add +} + +define float @fsub_p0_ieee_daz(float %arg0) #2 { +; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define float @fsub_p0_ieee_daz +; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR8]] { +; CHECK-NEXT: [[SUB:%.*]] = fsub float [[ARG0]], 0.000000e+00 +; CHECK-NEXT: ret float [[SUB]] +; + %sub = fsub float %arg0, 0.0 + ret float %sub +} + +define float @fsub_n0_ieee_daz(float %arg0) #2 { +; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define nofpclass(nzero) float @fsub_n0_ieee_daz +; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR8]] { +; CHECK-NEXT: [[SUB:%.*]] = fsub float [[ARG0]], -0.000000e+00 +; CHECK-NEXT: ret float [[SUB]] +; + %sub = fsub float %arg0, -0.0 + ret float %sub +} + +define float @fsub_p0_commute_ieee_daz(float %arg0) #2 { +; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define float @fsub_p0_commute_ieee_daz +; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR8]] { +; CHECK-NEXT: [[SUB:%.*]] = fsub float 0.000000e+00, [[ARG0]] +; CHECK-NEXT: ret float [[SUB]] +; + %sub = fsub float 0.0, %arg0 + ret float %sub +} + +define float @fsub_n0_commute_ieee_daz(float %arg0) #1 { +; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define float @fsub_n0_commute_ieee_daz +; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR10:[0-9]+]] { +; CHECK-NEXT: [[SUB:%.*]] = fsub float -0.000000e+00, [[ARG0]] +; CHECK-NEXT: ret float [[SUB]] +; + %sub = fsub float -0.0, %arg0 + ret float %sub +} + +define float @fadd_never_negzero_or_negsub(float nofpclass(nzero nsub) %a, float nofpclass(nzero nsub) %b) { +; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define nofpclass(nzero) float @fadd_never_negzero_or_negsub +; CHECK-SAME: (float nofpclass(nzero nsub) [[A:%.*]], float nofpclass(nzero nsub) [[B:%.*]]) #[[ATTR2]] { +; CHECK-NEXT: [[ADD:%.*]] = fadd float [[A]], [[B]] +; CHECK-NEXT: ret float [[ADD]] +; + %add = fadd float %a, %b + ret float %add +} + +define float @fadd_never_negzero_or_negsub_daz(float nofpclass(nzero nsub) %a, float nofpclass(nzero nsub) %b) #2 { +; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define nofpclass(nzero) float @fadd_never_negzero_or_negsub_daz +; CHECK-SAME: (float nofpclass(nzero nsub) [[A:%.*]], float nofpclass(nzero nsub) [[B:%.*]]) #[[ATTR8]] { +; CHECK-NEXT: [[ADD:%.*]] = fadd float [[A]], [[B]] +; CHECK-NEXT: ret float [[ADD]] +; + %add = fadd float %a, %b + ret float %add +} + +define float @fadd_never_negzero_or_negsub_dapz(float nofpclass(nzero nsub) %a, float nofpclass(nzero nsub) %b) #5 { +; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define nofpclass(nzero) float @fadd_never_negzero_or_negsub_dapz +; CHECK-SAME: (float nofpclass(nzero nsub) [[A:%.*]], float nofpclass(nzero nsub) [[B:%.*]]) #[[ATTR11:[0-9]+]] { +; CHECK-NEXT: [[ADD:%.*]] = fadd float [[A]], [[B]] +; CHECK-NEXT: ret float [[ADD]] +; + %add = fadd float %a, %b + ret float %add +} + +define float @fadd_never_negzero_or_possub(float nofpclass(nzero psub) %a, float nofpclass(nzero psub) %b) { +; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define nofpclass(nzero) float @fadd_never_negzero_or_possub +; CHECK-SAME: (float nofpclass(nzero psub) [[A:%.*]], float nofpclass(nzero psub) [[B:%.*]]) #[[ATTR2]] { +; CHECK-NEXT: [[ADD:%.*]] = fadd float [[A]], [[B]] +; CHECK-NEXT: ret float [[ADD]] +; + %add = fadd float %a, %b + ret float %add +} + +define float @fadd_never_negzero_or_possub_daz(float nofpclass(nzero psub) %a, float nofpclass(nzero psub) %b) #2 { +; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define float @fadd_never_negzero_or_possub_daz +; CHECK-SAME: (float nofpclass(nzero psub) [[A:%.*]], float nofpclass(nzero psub) [[B:%.*]]) #[[ATTR8]] { +; CHECK-NEXT: [[ADD:%.*]] = fadd float [[A]], [[B]] +; CHECK-NEXT: ret float [[ADD]] +; + %add = fadd float %a, %b + ret float %add +} + +define float @fadd_never_negzero_or_possub_dapz(float nofpclass(nzero psub) %a, float nofpclass(nzero psub) %b) #5 { +; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define nofpclass(nzero) float @fadd_never_negzero_or_possub_dapz +; CHECK-SAME: (float nofpclass(nzero psub) [[A:%.*]], float nofpclass(nzero psub) [[B:%.*]]) #[[ATTR11]] { +; CHECK-NEXT: [[ADD:%.*]] = fadd float [[A]], [[B]] +; CHECK-NEXT: ret float [[ADD]] +; + %add = fadd float %a, %b + ret float %add +} + +define float @fadd_never_negzero_or_sub_daz(float nofpclass(nzero sub) %a, float nofpclass(nzero sub) %b) #2 { +; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define nofpclass(nzero) float @fadd_never_negzero_or_sub_daz +; CHECK-SAME: (float nofpclass(nzero sub) [[A:%.*]], float nofpclass(nzero sub) [[B:%.*]]) #[[ATTR8]] { +; CHECK-NEXT: [[ADD:%.*]] = fadd float [[A]], [[B]] +; CHECK-NEXT: ret float [[ADD]] +; + %add = fadd float %a, %b + ret float %add +} + +define float @fadd_never_negzero_or_sub_dapz(float nofpclass(nzero sub) %a, float nofpclass(nzero sub) %b) #5 { +; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define nofpclass(nzero) float @fadd_never_negzero_or_sub_dapz +; CHECK-SAME: (float nofpclass(nzero sub) [[A:%.*]], float nofpclass(nzero sub) [[B:%.*]]) #[[ATTR11]] { +; CHECK-NEXT: [[ADD:%.*]] = fadd float [[A]], [[B]] +; CHECK-NEXT: ret float [[ADD]] +; + %add = fadd float %a, %b + ret float %add +} + +define float @fadd_known_positive_lhs(float nofpclass(ninf nsub nnorm) %arg0, float %arg1) { +; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define float @fadd_known_positive_lhs +; CHECK-SAME: (float nofpclass(ninf nsub nnorm) [[ARG0:%.*]], float [[ARG1:%.*]]) #[[ATTR2]] { +; CHECK-NEXT: [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]] +; CHECK-NEXT: ret float [[ADD]] +; + %add = fadd float %arg0, %arg1 + ret float %add +} + +define float @fadd_known_positive_rhs(float %arg0, float nofpclass(ninf nsub nnorm) %arg1) { +; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define float @fadd_known_positive_rhs +; CHECK-SAME: (float [[ARG0:%.*]], float nofpclass(ninf nsub nnorm) [[ARG1:%.*]]) #[[ATTR2]] { +; CHECK-NEXT: [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]] +; CHECK-NEXT: ret float [[ADD]] +; + %add = fadd float %arg0, %arg1 + ret float %add +} + +define float @fadd_known_positive(float nofpclass(ninf nsub nnorm) %arg0, float nofpclass(ninf nsub nnorm) %arg1) { +; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define float @fadd_known_positive +; CHECK-SAME: (float nofpclass(ninf nsub nnorm) [[ARG0:%.*]], float nofpclass(ninf nsub nnorm) [[ARG1:%.*]]) #[[ATTR2]] { +; CHECK-NEXT: [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]] +; CHECK-NEXT: ret float [[ADD]] +; + %add = fadd float %arg0, %arg1 + ret float %add +} + +define float @fadd_known_positive_daz(float nofpclass(ninf nsub nnorm) %arg0, float nofpclass(ninf nsub nnorm) %arg1) #0 { +; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define float @fadd_known_positive_daz +; CHECK-SAME: (float nofpclass(ninf nsub nnorm) [[ARG0:%.*]], float nofpclass(ninf nsub nnorm) [[ARG1:%.*]]) #[[ATTR7]] { +; CHECK-NEXT: [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]] +; CHECK-NEXT: ret float [[ADD]] +; + %add = fadd float %arg0, %arg1 + ret float %add +} + +define float @fadd_known_positive_nzero_lhs(float nofpclass(ninf nsub nnorm nzero) %arg0, float nofpclass(ninf nsub nnorm) %arg1) { +; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define float @fadd_known_positive_nzero_lhs +; CHECK-SAME: (float nofpclass(ninf nzero nsub nnorm) [[ARG0:%.*]], float nofpclass(ninf nsub nnorm) [[ARG1:%.*]]) #[[ATTR2]] { +; CHECK-NEXT: [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]] +; CHECK-NEXT: ret float [[ADD]] +; + %add = fadd float %arg0, %arg1 + ret float %add +} + +define float @fadd_known_positive_nzero_rhs(float nofpclass(ninf nsub nnorm) %arg0, float nofpclass(ninf nsub nnorm nzero) %arg1) { +; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define nofpclass(nzero) float @fadd_known_positive_nzero_rhs +; CHECK-SAME: (float nofpclass(ninf nsub nnorm) [[ARG0:%.*]], float nofpclass(ninf nzero nsub nnorm) [[ARG1:%.*]]) #[[ATTR2]] { +; CHECK-NEXT: [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]] +; CHECK-NEXT: ret float [[ADD]] +; + %add = fadd float %arg0, %arg1 + ret float %add +} + +define float @fadd_known_positive_nzero(float nofpclass(ninf nsub nnorm nzero) %arg0, float nofpclass(ninf nsub nnorm nzero) %arg1) { +; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define nofpclass(nzero) float @fadd_known_positive_nzero +; CHECK-SAME: (float nofpclass(ninf nzero nsub nnorm) [[ARG0:%.*]], float nofpclass(ninf nzero nsub nnorm) [[ARG1:%.*]]) #[[ATTR2]] { +; CHECK-NEXT: [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]] +; CHECK-NEXT: ret float [[ADD]] +; + %add = fadd float %arg0, %arg1 + ret float %add +} + +define float @fadd_known_positive_nzero_ftz_daz(float nofpclass(ninf nsub nnorm nzero) %arg0, float nofpclass(ninf nsub nnorm nzero) %arg1) #0 { +; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define float @fadd_known_positive_nzero_ftz_daz +; CHECK-SAME: (float nofpclass(ninf nzero nsub nnorm) [[ARG0:%.*]], float nofpclass(ninf nzero nsub nnorm) [[ARG1:%.*]]) #[[ATTR7]] { +; CHECK-NEXT: [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]] +; CHECK-NEXT: ret float [[ADD]] +; + %add = fadd float %arg0, %arg1 + ret float %add +} + +define float @fadd_known_positive_nzero_ftz(float nofpclass(ninf nsub nnorm nzero) %arg0, float nofpclass(ninf nsub nnorm nzero) %arg1) #1 { +; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define float @fadd_known_positive_nzero_ftz +; CHECK-SAME: (float nofpclass(ninf nzero nsub nnorm) [[ARG0:%.*]], float nofpclass(ninf nzero nsub nnorm) [[ARG1:%.*]]) #[[ATTR10]] { +; CHECK-NEXT: [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]] +; CHECK-NEXT: ret float [[ADD]] +; + %add = fadd float %arg0, %arg1 + ret float %add +} + +define float @fadd_known_positive_nzero_daz(float nofpclass(ninf nsub nnorm nzero) %arg0, float nofpclass(ninf nsub nnorm nzero) %arg1) #2 { +; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define nofpclass(nzero) float @fadd_known_positive_nzero_daz +; CHECK-SAME: (float nofpclass(ninf nzero nsub nnorm) [[ARG0:%.*]], float nofpclass(ninf nzero nsub nnorm) [[ARG1:%.*]]) #[[ATTR8]] { +; CHECK-NEXT: [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]] +; CHECK-NEXT: ret float [[ADD]] +; + %add = fadd float %arg0, %arg1 + ret float %add +} + +define float @fadd_known_positive_normal(float nofpclass(ninf nnorm nzero) %arg0, float nofpclass(ninf nnorm nzero) %arg1) { +; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define nofpclass(nzero) float @fadd_known_positive_normal +; CHECK-SAME: (float nofpclass(ninf nzero nnorm) [[ARG0:%.*]], float nofpclass(ninf nzero nnorm) [[ARG1:%.*]]) #[[ATTR2]] { +; CHECK-NEXT: [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]] +; CHECK-NEXT: ret float [[ADD]] +; + %add = fadd float %arg0, %arg1 + ret float %add +} + +define float @fadd_known_positive_normal_daz(float nofpclass(ninf nnorm nzero) %arg0, float nofpclass(ninf nnorm nzero) %arg1) #0 { +; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define float @fadd_known_positive_normal_daz +; CHECK-SAME: (float nofpclass(ninf nzero nnorm) [[ARG0:%.*]], float nofpclass(ninf nzero nnorm) [[ARG1:%.*]]) #[[ATTR7]] { +; CHECK-NEXT: [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]] +; CHECK-NEXT: ret float [[ADD]] +; + %add = fadd float %arg0, %arg1 + ret float %add +} + +define float @fadd_known_positive_normal_except0_daz(float nofpclass(ninf nnorm) %arg0, float nofpclass(ninf nnorm) %arg1) #0 { +; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define float @fadd_known_positive_normal_except0_daz +; CHECK-SAME: (float nofpclass(ninf nnorm) [[ARG0:%.*]], float nofpclass(ninf nnorm) [[ARG1:%.*]]) #[[ATTR7]] { +; CHECK-NEXT: [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]] +; CHECK-NEXT: ret float [[ADD]] +; + %add = fadd float %arg0, %arg1 + ret float %add +} + +define float @fadd_known_positive_normal_dapz(float nofpclass(ninf nnorm nzero) %arg0, float nofpclass(ninf nnorm nzero) %arg1) #3 { +; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define nofpclass(nzero) float @fadd_known_positive_normal_dapz +; CHECK-SAME: (float nofpclass(ninf nzero nnorm) [[ARG0:%.*]], float nofpclass(ninf nzero nnorm) [[ARG1:%.*]]) #[[ATTR6]] { +; CHECK-NEXT: [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]] +; CHECK-NEXT: ret float [[ADD]] +; + %add = fadd float %arg0, %arg1 + ret float %add +} + +attributes #0 = { "denormal-fp-math"="preserve-sign,preserve-sign" } +attributes #1 = { "denormal-fp-math"="preserve-sign,ieee" } +attributes #2 = { "denormal-fp-math"="ieee,preserve-sign" } +attributes #3 = { "denormal-fp-math"="positive-zero,positive-zero" } +attributes #4 = { "denormal-fp-math"="positive-zero,ieee" } +attributes #5 = { "denormal-fp-math"="ieee,positive-zero" }