Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Transforms] Resolve FIXME: No Lowering of FNeg to FMul unless it is safe #85252

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

AtariDreams
Copy link
Contributor

Or association flags are specified.

@llvmbot
Copy link
Collaborator

llvmbot commented Mar 14, 2024

@llvm/pr-subscribers-llvm-transforms

Author: AtariDreams (AtariDreams)

Changes

Or association flags are specified.


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

1 Files Affected:

  • (modified) llvm/lib/Transforms/Scalar/Reassociate.cpp (+9-3)
diff --git a/llvm/lib/Transforms/Scalar/Reassociate.cpp b/llvm/lib/Transforms/Scalar/Reassociate.cpp
index d91320863e241d..f44608624cf3df 100644
--- a/llvm/lib/Transforms/Scalar/Reassociate.cpp
+++ b/llvm/lib/Transforms/Scalar/Reassociate.cpp
@@ -287,11 +287,17 @@ static Instruction *CreateNeg(Value *S1, const Twine &Name,
 static BinaryOperator *LowerNegateToMultiply(Instruction *Neg) {
   assert((isa<UnaryOperator>(Neg) || isa<BinaryOperator>(Neg)) &&
          "Expected a Negate!");
-  // FIXME: It's not safe to lower a unary FNeg into a FMul by -1.0.
   unsigned OpNo = isa<BinaryOperator>(Neg) ? 1 : 0;
   Type *Ty = Neg->getType();
-  Constant *NegOne = Ty->isIntOrIntVectorTy() ?
-    ConstantInt::getAllOnesValue(Ty) : ConstantFP::get(Ty, -1.0);
+
+  // Only lower to FMul if the operation is not a unary FNeg or Neg has the
+  // correct flags.
+  if (Ty->isFloatingPointTy() && isa<UnaryOperator>(Neg) &&
+      !hasFPAssociativeFlags(Neg))
+    return nullptr;
+
+  Constant *NegOne = Ty->isIntOrIntVectorTy() ? ConstantInt::getAllOnesValue(Ty)
+                                              : ConstantFP::get(Ty, -1.0);
 
   BinaryOperator *Res =
       CreateMul(Neg->getOperand(OpNo), NegOne, "", Neg->getIterator(), Neg);

@dtcxzyw
Copy link
Member

dtcxzyw commented Mar 14, 2024

Could you please provide the proof? I cannot prove the correctness with alive2.

@nikic nikic changed the title [Scalar] Resolve FIXME: No Lowering of FNeg to FMul unless it is safe [Reassociate] Resolve FIXME: No Lowering of FNeg to FMul unless it is safe Mar 14, 2024
@dtcxzyw
Copy link
Member

dtcxzyw commented Mar 14, 2024

https://alive2.llvm.org/ce/z/Ki3Rf2

nnan is all you need :)

Copy link

github-actions bot commented Mar 14, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

@AtariDreams AtariDreams changed the title [Reassociate] Resolve FIXME: No Lowering of FNeg to FMul unless it is safe [Transforms] Resolve FIXME: No Lowering of FNeg to FMul unless it is safe Mar 14, 2024
@AtariDreams AtariDreams force-pushed the todo-again branch 2 times, most recently from cf284e9 to 199fb5e Compare March 14, 2024 18:56
@arsenm
Copy link
Contributor

arsenm commented Mar 15, 2024

https://alive2.llvm.org/ce/z/Ki3Rf2

nnan is all you need :)

In this context, it's not simply doing this transform in isolation. It's being consumed by another canonicalizing operation. The problem is this is introducing a canonicalization, which doesn't matter if it's only used by operations that canonicalize the inputs. nnan would not be sufficient to introduce this, since operations may also do other bit pattern changing side effects (like denormal flush). Since this is consumed by a canonicalizing operation, it's either correct to always do (in the has one use case) (or it's wrong to ever do).

ConstantInt::getAllOnesValue(Ty) : ConstantFP::get(Ty, -1.0);
// Only lower to FMul if the operation is not a unary FNeg or Neg has the
// correct flags.
if (Ty->isFPOrFPVectorTy() && isa<UnaryOperator>(Neg) && !Neg->hasNoNaNs())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better to directly check for fneg? isa that's floating point type isn't really obvious

Comment on lines +592 to +594
%b = fmul fast float %a, -2.0
%neg = fneg fast float %a
%mul = fmul fast float %neg, %b
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't need the full set of fast flags. Also don't need it on every instruction. Should target testing missing specific flags contexts

%neg = fneg fast nnan <4 x float> %a
%mul = fmul fast <4 x float> %neg, %b
ret <4 x float> %mul
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also add test where it's know not-nan from the source

@arsenm
Copy link
Contributor

arsenm commented Mar 15, 2024

which doesn't matter if it's only used by operations that canonicalize the inputs.

I guess we technically don't guarantee canonicalization on FP operations, but I think we can assert that it may happen

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants