Please use GitHub pull requests for new patches. Avoid migrating existing patches. Phabricator shutdown timeline
Changeset View
Standalone View
llvm/lib/Analysis/InstructionSimplify.cpp
Show First 20 Lines • Show All 4,896 Lines • ▼ Show 20 Lines | SimplifyFAddInst(Value *Op0, Value *Op1, FastMathFlags FMF, | ||||
RoundingMode Rounding = RoundingMode::NearestTiesToEven) { | RoundingMode Rounding = RoundingMode::NearestTiesToEven) { | ||||
if (isDefaultFPEnvironment(ExBehavior, Rounding)) | if (isDefaultFPEnvironment(ExBehavior, Rounding)) | ||||
if (Constant *C = foldOrCommuteConstant(Instruction::FAdd, Op0, Op1, Q)) | if (Constant *C = foldOrCommuteConstant(Instruction::FAdd, Op0, Op1, Q)) | ||||
return C; | return C; | ||||
if (Constant *C = simplifyFPOp({Op0, Op1}, FMF, Q, ExBehavior, Rounding)) | if (Constant *C = simplifyFPOp({Op0, Op1}, FMF, Q, ExBehavior, Rounding)) | ||||
return C; | return C; | ||||
if (!isDefaultFPEnvironment(ExBehavior, Rounding)) | |||||
return nullptr; | |||||
// fadd X, -0 ==> X | // fadd X, -0 ==> X | ||||
if (isDefaultFPEnvironment(ExBehavior, Rounding) || | |||||
(!RoundingModeMayBe(Rounding, RoundingMode::TowardNegative) && | |||||
(ExBehavior != fp::ebStrict || FMF.noNaNs()))) | |||||
sepavloff: Even if `ExBehavior != fp::ebStrict` this transformation is invalid if `X` is SNaN, the latter… | |||||
Can I put this in a different patch? We have the same issue for constrained and non-constrained cases, and we don't have a good way to distinguish them -- nor should we. Most of the required code is present in APFloat, but not all. Would it be OK for me to add the needed bits to APFloat and use them from InstSimplify in a different ticket? kpn: Can I put this in a different patch? We have the same issue for constrained and non-constrained… | |||||
Not Done ReplyInline ActionsI am not sure I understand what you are going to put into another patch. The transformation: fadd X, -0 ==> X is valid only if X != SNaN, otherwise we have: fadd SNaN, -0 ==> QNaN It does not depend on whether FP environment is default or not, the code before your changes was already incorrect. Such transformation is valid if the operation has flag nnan, but not in general case. Code in APFloat hardly can help, as constant folding is made previously, if X is a constant here, it means it cannot be folded. sepavloff: I am not sure I understand what you are going to put into another patch. The transformation… | |||||
Not Done ReplyInline ActionsIIUC, you are saying SNaN vs. QNaN is more than just a part of the exception state. But that's not how I interpret the current LangRef: ...and that's why *none* of the transforms here are intentionally SNaN preserving/clearing. If we are going to change the behavior of the default FP env, the LangRef must be updated to make that clear. I don't see the motivation yet. spatel: IIUC, you are saying SNaN vs. QNaN is more than just a part of the exception state. But that's… | |||||
Not Done ReplyInline ActionsThat's true for default FP environment. A difference between SNaN and QNaN is that operations on SNaN raise invalid exception. In default FP environment exceptions are ignored so SNaN and QNaN behave identically. But this code works in non-default FP environment as well. fadd here designates both regular IR node used in default environment as well as its constrained counterpart. So SNaN here must be handled more carefully. sepavloff: That's true for default FP environment. A difference between SNaN and QNaN is that operations… | |||||
Not Done ReplyInline ActionsThis seems to be getting fuzzy when the exception state is "MayTrap", so we probably need to clarify that definition in the LangRef. Is there a regression test below that shows where you think this patch is wrong? I think the fold is correct with MayTrap (assuming the rounding mode is known suitable) because "passes are not required to preserve all exceptions that are implied by the original code"; presumably some other operation is eventually going to generate the invalid exception when it sees the SNaN? spatel: This seems to be getting fuzzy when the exception state is "MayTrap", so we probably need to… | |||||
We won't see a NaN here if 'nnan' is specified since simplifyFPOp() will have already turned it to poison and returned. So I think the check for FMF.noNaNs() should be removed since it can't happen and is therefore misleading. We won't fold in the 'strict' exception case because we check for it and reject it. I suspect the real objection is that we're not turning a SNaN into a QNaN here. But with the constant folding that Serge recently added we won't even be here in the "ignore" or "maytrap" cases at all. There won't be a "fadd NaN, -0" case except in the "strict" exception case which we decline to fold. Aside from the unneeded check for FMF.noNaNs() I don't see a problem here. We aren't returning the wrong result here or below. And I do now have code for the APFloat and ConstantFP classes to make it easy for simplifyFPOp() to convert SNaN->QNaN. That's what I was planning on submitting in a different ticket. kpn: We won't see a NaN here if 'nnan' is specified since simplifyFPOp() will have already turned it… | |||||
Actually, the check for FMF.noNaNs() is required to catch non-constants. We can still fold "fadd X, -0" if we know X is not a NaN. We still have the "trivially dead" issue where the instruction would be hanging around needlessly, but still... kpn: Actually, the check for FMF.noNaNs() is required to catch non-constants. We can still fold… | |||||
Rereading @spatel's comment: what about the "X is a variable that happens to have the value of an SNaN" case: it's true that we'll be removing an instruction that would have converted the SNaN to a QNaN. So the removal of the instruction would be observable. I don't see a way around that without eliminating the ability to optimize at all. kpn: Rereading @spatel's comment: what about the "X is a variable that happens to have the value of… | |||||
Not Done ReplyInline ActionsI don't think you can make this transformation in the "maytrap" case. It would be ok to optimize an SNaN to a QNaN, but you can't eliminate an instruction that would raise the exception while performing the same conversion. Consider this example: double foo(double x, double y) { #pragma clang fp exceptions(maytrap) double temp; feclearexcept(FE_ALL_EXCEPT); temp = x + -0.0; // Check the x = SNaN case if (fetestexcept(FE_INEXACT)) return -1.0; temp = temp + y; // Check the y = SNaN case if (fetestexcept(FE_INEXACT)) return -2.0; return temp; } Eliminating the fadd x, -0 causes the exception to be raised in the wrong place. andrew.w.kaylor: I don't think you can make this transformation in the "maytrap" case. It would be ok to… | |||||
Not Done ReplyInline ActionsThe transformation fadd X, -0 ==> X is wrong in the two cases:
It is not correct to produce SNaN instead of QNaN. This result might be stored somewhere and could further be processed by other code, which operates in strict mode. Such transformation would cause that code to trap. Behavior of the code with this transformation and without it would be different. So this transformation is safe only if FMF.noNans(). The proposed condition is: if ((!RoundingModeMayBe(Rounding, RoundingMode::TowardNegative) || FMF.noSignedZeros()) && FMF.noNaNs()) sepavloff: The transformation `fadd X, -0 ==> X` is wrong in the two cases:
1. When the rounding mode is… | |||||
if (match(Op1, m_NegZeroFP())) | if (match(Op1, m_NegZeroFP())) | ||||
return Op0; | return Op0; | ||||
// fadd X, 0 ==> X, when we know X is not -0 | // fadd X, 0 ==> X, when we know X is not -0 | ||||
if (isDefaultFPEnvironment(ExBehavior, Rounding) || | |||||
(ExBehavior != fp::ebStrict || FMF.noNaNs())) | |||||
Not Done ReplyInline ActionsThe same about X==SNaN. sepavloff: The same about `X==SNaN`. | |||||
if (match(Op1, m_PosZeroFP()) && | if (match(Op1, m_PosZeroFP()) && | ||||
(FMF.noSignedZeros() || CannotBeNegativeZero(Op0, Q.TLI))) | (FMF.noSignedZeros() || CannotBeNegativeZero(Op0, Q.TLI))) | ||||
return Op0; | return Op0; | ||||
if (!isDefaultFPEnvironment(ExBehavior, Rounding)) | |||||
return nullptr; | |||||
// With nnan: -X + X --> 0.0 (and commuted variant) | // With nnan: -X + X --> 0.0 (and commuted variant) | ||||
Not Done ReplyInline ActionsWhat about making such transformation in non-default mode? sepavloff: What about making such transformation in non-default mode? | |||||
It requires adding support to the IR matchers like m_FSub(), and those are used elsewhere. Which implies testing in places in addition to here. So I'm saving that for a subsequent patch. Small steps. kpn: It requires adding support to the IR matchers like m_FSub(), and those are used elsewhere. | |||||
Actually, the check for the default FP environment isn't needed. No matcher support has been done yet. The matchers won't match so there's no need for the guard. kpn: Actually, the check for the default FP environment isn't needed. No matcher support has been… | |||||
Not Done ReplyInline ActionsAccording to https://en.wikipedia.org/wiki/Signed_zero: "x-x=x+(-x)=+0 (for any finite x, -0 when rounding toward negative)" So the check for rounding mode is also necessary, unless FMF.noSignedZero(). sepavloff: According to https://en.wikipedia.org/wiki/Signed_zero:
"x-x=x+(-x)=+0 (for any finite x, -0… | |||||
// We don't have to explicitly exclude infinities (ninf): INF + -INF == NaN. | // We don't have to explicitly exclude infinities (ninf): INF + -INF == NaN. | ||||
// Negative zeros are allowed because we always end up with positive zero: | // Negative zeros are allowed because we always end up with positive zero: | ||||
// X = -0.0: (-0.0 - (-0.0)) + (-0.0) == ( 0.0) + (-0.0) == 0.0 | // X = -0.0: (-0.0 - (-0.0)) + (-0.0) == ( 0.0) + (-0.0) == 0.0 | ||||
// X = -0.0: ( 0.0 - (-0.0)) + (-0.0) == ( 0.0) + (-0.0) == 0.0 | // X = -0.0: ( 0.0 - (-0.0)) + (-0.0) == ( 0.0) + (-0.0) == 0.0 | ||||
// X = 0.0: (-0.0 - ( 0.0)) + ( 0.0) == (-0.0) + ( 0.0) == 0.0 | // X = 0.0: (-0.0 - ( 0.0)) + ( 0.0) == (-0.0) + ( 0.0) == 0.0 | ||||
// X = 0.0: ( 0.0 - ( 0.0)) + ( 0.0) == ( 0.0) + ( 0.0) == 0.0 | // X = 0.0: ( 0.0 - ( 0.0)) + ( 0.0) == ( 0.0) + ( 0.0) == 0.0 | ||||
if (FMF.noNaNs()) { | if (FMF.noNaNs()) { | ||||
if (match(Op0, m_FSub(m_AnyZeroFP(), m_Specific(Op1))) || | if (match(Op0, m_FSub(m_AnyZeroFP(), m_Specific(Op1))) || | ||||
▲ Show 20 Lines • Show All 1,412 Lines • Show Last 20 Lines |
Even if ExBehavior != fp::ebStrict this transformation is invalid if X is SNaN, the latter must be converted to QNaN.