[llvm] [InstSimplify] Treat float binop with identity as refining (PR #120098)
Nikita Popov via llvm-commits
llvm-commits at lists.llvm.org
Mon Dec 16 07:33:46 PST 2024
https://github.com/nikic created https://github.com/llvm/llvm-project/pull/120098
If x if NaN, then fmul (x, 1) may produce a different NaN value.
Our float semantics explicitly permit folding fmul (x, 1) to x, but we can't do this when we're replacing a select input, as selects are supposed to preserve the exact bitwise value.
Fixes https://github.com/llvm/llvm-project/pull/115152#issuecomment-2545773114.
>From f2a97a403b916e8b386cb7e466addbf762dd3b4c Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Mon, 16 Dec 2024 16:30:48 +0100
Subject: [PATCH] [InstSimplify] Treat float binop with identity as refining
If x if NaN, then fmul (x, 1) may produce a different NaN value.
Our float semantics explicitly permit folding fmul (x, 1) to x,
but we can't do this when we're replacing a select input, as
selects are supposed to preserve the exact bitwise value.
---
llvm/lib/Analysis/InstructionSimplify.cpp | 13 ++++++++-----
.../InstSimplify/select-equivalence-fp.ll | 14 ++++++++++----
2 files changed, 18 insertions(+), 9 deletions(-)
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 3325cd972cf1eb..726c0f29e39928 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -4345,11 +4345,14 @@ static Value *simplifyWithOpReplaced(Value *V, Value *Op, Value *RepOp,
if (auto *BO = dyn_cast<BinaryOperator>(I)) {
unsigned Opcode = BO->getOpcode();
// id op x -> x, x op id -> x
- if (NewOps[0] == ConstantExpr::getBinOpIdentity(Opcode, I->getType()))
- return NewOps[1];
- if (NewOps[1] == ConstantExpr::getBinOpIdentity(Opcode, I->getType(),
- /* RHS */ true))
- return NewOps[0];
+ // Exclude floats, because x op id may produce a different NaN value.
+ if (!BO->getType()->isFPOrFPVectorTy()) {
+ if (NewOps[0] == ConstantExpr::getBinOpIdentity(Opcode, I->getType()))
+ return NewOps[1];
+ if (NewOps[1] == ConstantExpr::getBinOpIdentity(Opcode, I->getType(),
+ /* RHS */ true))
+ return NewOps[0];
+ }
// x & x -> x, x | x -> x
if ((Opcode == Instruction::And || Opcode == Instruction::Or) &&
diff --git a/llvm/test/Transforms/InstSimplify/select-equivalence-fp.ll b/llvm/test/Transforms/InstSimplify/select-equivalence-fp.ll
index 8af751d0a4246d..81132029466f90 100644
--- a/llvm/test/Transforms/InstSimplify/select-equivalence-fp.ll
+++ b/llvm/test/Transforms/InstSimplify/select-equivalence-fp.ll
@@ -114,10 +114,14 @@ define <2 x float> @select_fcmp_fadd_vec(<2 x float> %x) {
}
+; Should not fold, because the fmul by identity may produce a different NaN
+; value.
define float @select_fcmp_fmul_nonrefinement(float %x, float %y) {
; CHECK-LABEL: @select_fcmp_fmul_nonrefinement(
-; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[Y:%.*]], [[X:%.*]]
-; CHECK-NEXT: ret float [[FMUL]]
+; CHECK-NEXT: [[FCMP:%.*]] = fcmp oeq float [[X:%.*]], 1.000000e+00
+; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[Y:%.*]], [[X]]
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[FCMP]], float [[Y]], float [[FMUL]]
+; CHECK-NEXT: ret float [[SEL]]
;
%fcmp = fcmp oeq float %x, 1.0
%fmul = fmul float %y, %x
@@ -137,8 +141,10 @@ define float @select_fcmp_fmul(float %x) {
define float @select_fcmp_fdiv_nonrefinement(float %x, float %y) {
; CHECK-LABEL: @select_fcmp_fdiv_nonrefinement(
-; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[Y:%.*]], [[X:%.*]]
-; CHECK-NEXT: ret float [[FDIV]]
+; CHECK-NEXT: [[FCMP:%.*]] = fcmp oeq float [[X:%.*]], 1.000000e+00
+; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[Y:%.*]], [[X]]
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[FCMP]], float [[Y]], float [[FDIV]]
+; CHECK-NEXT: ret float [[SEL]]
;
%fcmp = fcmp oeq float %x, 1.0
%fdiv = fdiv float %y, %x
More information about the llvm-commits
mailing list