[llvm] InstSimplify: support floating-point equivalences (PR #115152)
Ramkumar Ramachandra via llvm-commits
llvm-commits at lists.llvm.org
Fri Nov 8 06:58:22 PST 2024
https://github.com/artagnon updated https://github.com/llvm/llvm-project/pull/115152
>From 455ef0346c1e5481283e5ed6ae4e5f9145f586bc Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra <ramkumar.ramachandra at codasip.com>
Date: Wed, 6 Nov 2024 11:39:26 +0000
Subject: [PATCH 1/2] InstSimplify: cover select folding for fp
In prepraration to extend select folding to include floating-points
using CmpInst::isEquivalence, cover it with tests first.
---
.../InstSimplify/select-equivalence-fp.ll | 293 ++++++++++++++++++
1 file changed, 293 insertions(+)
create mode 100644 llvm/test/Transforms/InstSimplify/select-equivalence-fp.ll
diff --git a/llvm/test/Transforms/InstSimplify/select-equivalence-fp.ll b/llvm/test/Transforms/InstSimplify/select-equivalence-fp.ll
new file mode 100644
index 00000000000000..bad6a532bd4db8
--- /dev/null
+++ b/llvm/test/Transforms/InstSimplify/select-equivalence-fp.ll
@@ -0,0 +1,293 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -passes=instsimplify -S | FileCheck %s
+
+define float @select_fcmp_fsub_oeq(float %x) {
+; CHECK-LABEL: @select_fcmp_fsub_oeq(
+; CHECK-NEXT: [[FCMP:%.*]] = fcmp oeq float [[X:%.*]], 2.000000e+00
+; CHECK-NEXT: [[FADD:%.*]] = fsub float [[X]], 2.000000e+00
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[FCMP]], float [[FADD]], float 0.000000e+00
+; CHECK-NEXT: ret float [[SEL]]
+;
+ %fcmp = fcmp oeq float %x, 2.0
+ %fadd = fsub float %x, 2.0
+ %sel = select i1 %fcmp, float %fadd, float 0.0
+ ret float %sel
+}
+
+define float @select_fcmp_fsub_oeq_zero(float %x) {
+; CHECK-LABEL: @select_fcmp_fsub_oeq_zero(
+; CHECK-NEXT: [[FCMP:%.*]] = fcmp oeq float [[X:%.*]], 0.000000e+00
+; CHECK-NEXT: [[FADD:%.*]] = fsub float [[X]], 2.000000e+00
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[FCMP]], float [[FADD]], float 2.000000e+00
+; CHECK-NEXT: ret float [[SEL]]
+;
+ %fcmp = fcmp oeq float %x, 0.0
+ %fadd = fsub float %x, 2.0
+ %sel = select i1 %fcmp, float %fadd, float 2.0
+ ret float %sel
+}
+
+define float @select_fcmp_fsub_ueq(float %x) {
+; CHECK-LABEL: @select_fcmp_fsub_ueq(
+; CHECK-NEXT: [[FCMP:%.*]] = fcmp ueq float [[X:%.*]], 2.000000e+00
+; CHECK-NEXT: [[FADD:%.*]] = fsub float [[X]], 2.000000e+00
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[FCMP]], float [[FADD]], float 0.000000e+00
+; CHECK-NEXT: ret float [[SEL]]
+;
+ %fcmp = fcmp ueq float %x, 2.0
+ %fadd = fsub float %x, 2.0
+ %sel = select i1 %fcmp, float %fadd, float 0.0
+ ret float %sel
+}
+
+define float @select_fcmp_fsub_ueq_nnan(float %x) {
+; CHECK-LABEL: @select_fcmp_fsub_ueq_nnan(
+; CHECK-NEXT: [[FCMP:%.*]] = fcmp nnan ueq float [[X:%.*]], 2.000000e+00
+; CHECK-NEXT: [[FADD:%.*]] = fsub float [[X]], 2.000000e+00
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[FCMP]], float [[FADD]], float 0.000000e+00
+; CHECK-NEXT: ret float [[SEL]]
+;
+ %fcmp = fcmp nnan ueq float %x, 2.0
+ %fadd = fsub float %x, 2.0
+ %sel = select i1 %fcmp, float %fadd, float 0.0
+ ret float %sel
+}
+
+define float @select_fcmp_fsub_une(float %x) {
+; CHECK-LABEL: @select_fcmp_fsub_une(
+; CHECK-NEXT: [[FCMP:%.*]] = fcmp une float [[X:%.*]], 2.000000e+00
+; CHECK-NEXT: [[FADD:%.*]] = fsub float [[X]], 2.000000e+00
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[FCMP]], float 0.000000e+00, float [[FADD]]
+; CHECK-NEXT: ret float [[SEL]]
+;
+ %fcmp = fcmp une float %x, 2.0
+ %fadd = fsub float %x, 2.0
+ %sel = select i1 %fcmp, float 0.0, float %fadd
+ ret float %sel
+}
+
+define float @select_fcmp_fsub_une_zero(float %x) {
+; CHECK-LABEL: @select_fcmp_fsub_une_zero(
+; CHECK-NEXT: [[FCMP:%.*]] = fcmp une float [[X:%.*]], 0.000000e+00
+; CHECK-NEXT: [[FADD:%.*]] = fsub float [[X]], 2.000000e+00
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[FCMP]], float 2.000000e+00, float [[FADD]]
+; CHECK-NEXT: ret float [[SEL]]
+;
+ %fcmp = fcmp une float %x, 0.0
+ %fadd = fsub float %x, 2.0
+ %sel = select i1 %fcmp, float 2.0, float %fadd
+ ret float %sel
+}
+
+define float @select_fcmp_fsub_one(float %x) {
+; CHECK-LABEL: @select_fcmp_fsub_one(
+; CHECK-NEXT: [[FCMP:%.*]] = fcmp one float [[X:%.*]], 2.000000e+00
+; CHECK-NEXT: [[FADD:%.*]] = fsub float [[X]], 2.000000e+00
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[FCMP]], float 0.000000e+00, float [[FADD]]
+; CHECK-NEXT: ret float [[SEL]]
+;
+ %fcmp = fcmp one float %x, 2.0
+ %fadd = fsub float %x, 2.0
+ %sel = select i1 %fcmp, float 0.0, float %fadd
+ ret float %sel
+}
+
+define float @select_fcmp_fsub_one_nnan(float %x) {
+; CHECK-LABEL: @select_fcmp_fsub_one_nnan(
+; CHECK-NEXT: [[FCMP:%.*]] = fcmp nnan one float [[X:%.*]], 2.000000e+00
+; CHECK-NEXT: [[FADD:%.*]] = fsub float [[X]], 2.000000e+00
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[FCMP]], float 0.000000e+00, float [[FADD]]
+; CHECK-NEXT: ret float [[SEL]]
+;
+ %fcmp = fcmp nnan one float %x, 2.0
+ %fadd = fsub float %x, 2.0
+ %sel = select i1 %fcmp, float 0.0, float %fadd
+ ret float %sel
+}
+
+define float @select_fcmp_fadd(float %x) {
+; CHECK-LABEL: @select_fcmp_fadd(
+; CHECK-NEXT: [[FCMP:%.*]] = fcmp oeq float [[X:%.*]], 2.000000e+00
+; CHECK-NEXT: [[FADD:%.*]] = fadd float [[X]], 2.000000e+00
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[FCMP]], float [[FADD]], float 4.000000e+00
+; CHECK-NEXT: ret float [[SEL]]
+;
+ %fcmp = fcmp oeq float %x, 2.0
+ %fadd = fadd float %x, 2.0
+ %sel = select i1 %fcmp, float %fadd, float 4.0
+ ret float %sel
+}
+
+define <2 x float> @select_fcmp_fadd_vec(<2 x float> %x) {
+; CHECK-LABEL: @select_fcmp_fadd_vec(
+; CHECK-NEXT: [[FCMP:%.*]] = fcmp oeq <2 x float> [[X:%.*]], splat (float 2.000000e+00)
+; CHECK-NEXT: [[FADD:%.*]] = fadd <2 x float> [[X]], splat (float 2.000000e+00)
+; CHECK-NEXT: [[SEL:%.*]] = select <2 x i1> [[FCMP]], <2 x float> [[FADD]], <2 x float> splat (float 4.000000e+00)
+; CHECK-NEXT: ret <2 x float> [[SEL]]
+;
+ %fcmp = fcmp oeq <2 x float> %x, <float 2.0, float 2.0>
+ %fadd = fadd <2 x float> %x, <float 2.0, float 2.0>
+ %sel = select <2 x i1> %fcmp, <2 x float> %fadd, <2 x float> <float 4.0, float 4.0>
+ ret <2 x float> %sel
+}
+
+
+define float @select_fcmp_fmul_nonrefinement(float %x, float %y) {
+; CHECK-LABEL: @select_fcmp_fmul_nonrefinement(
+; 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
+ %sel = select i1 %fcmp, float %y, float %fmul
+ ret float %sel
+}
+
+define float @select_fcmp_fmul(float %x) {
+; CHECK-LABEL: @select_fcmp_fmul(
+; CHECK-NEXT: [[FCMP:%.*]] = fcmp oeq float [[X:%.*]], 2.000000e+00
+; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[X]], 2.000000e+00
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[FCMP]], float [[FMUL]], float 4.000000e+00
+; CHECK-NEXT: ret float [[SEL]]
+;
+ %fcmp = fcmp oeq float %x, 2.0
+ %fmul = fmul float %x, 2.0
+ %sel = select i1 %fcmp, float %fmul, float 4.0
+ ret float %sel
+}
+
+define float @select_fcmp_fdiv_nonrefinement(float %x, float %y) {
+; CHECK-LABEL: @select_fcmp_fdiv_nonrefinement(
+; 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
+ %sel = select i1 %fcmp, float %y, float %fdiv
+ ret float %sel
+}
+
+define float @select_fcmp_fdiv(float %x) {
+; CHECK-LABEL: @select_fcmp_fdiv(
+; CHECK-NEXT: [[FCMP:%.*]] = fcmp oeq float [[X:%.*]], 2.000000e+00
+; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[X]], 2.000000e+00
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[FCMP]], float [[FDIV]], float 1.000000e+00
+; CHECK-NEXT: ret float [[SEL]]
+;
+ %fcmp = fcmp oeq float %x, 2.0
+ %fdiv = fdiv float %x, 2.0
+ %sel = select i1 %fcmp, float %fdiv, float 1.0
+ ret float %sel
+}
+
+define float @select_fcmp_frem(float %x) {
+; CHECK-LABEL: @select_fcmp_frem(
+; CHECK-NEXT: [[FCMP:%.*]] = fcmp oeq float [[X:%.*]], 3.000000e+00
+; CHECK-NEXT: [[FREM:%.*]] = frem float [[X]], 2.000000e+00
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[FCMP]], float [[FREM]], float 1.000000e+00
+; CHECK-NEXT: ret float [[SEL]]
+;
+ %fcmp = fcmp oeq float %x, 3.0
+ %frem = frem float %x, 2.0
+ %sel = select i1 %fcmp, float %frem, float 1.0
+ ret float %sel
+}
+
+define <2 x float> @select_fcmp_insertelement(<2 x float> %x) {
+; CHECK-LABEL: @select_fcmp_insertelement(
+; CHECK-NEXT: [[FCMP:%.*]] = fcmp oeq <2 x float> [[X:%.*]], splat (float 2.000000e+00)
+; CHECK-NEXT: [[INSERT:%.*]] = insertelement <2 x float> [[X]], float 4.000000e+00, i64 0
+; CHECK-NEXT: [[SEL:%.*]] = select <2 x i1> [[FCMP]], <2 x float> [[INSERT]], <2 x float> <float 4.000000e+00, float 2.000000e+00>
+; CHECK-NEXT: ret <2 x float> [[SEL]]
+;
+ %fcmp = fcmp oeq <2 x float> %x, <float 2.0, float 2.0>
+ %insert = insertelement <2 x float> %x, float 4.0, i64 0
+ %sel = select <2 x i1> %fcmp, <2 x float> %insert, <2 x float> <float 4.0, float 2.0>
+ ret <2 x float> %sel
+}
+
+define <4 x float> @select_fcmp_shufflevector_select(<4 x float> %x) {
+; CHECK-LABEL: @select_fcmp_shufflevector_select(
+; CHECK-NEXT: [[FCMP:%.*]] = fcmp oeq <4 x float> [[X:%.*]], splat (float 2.000000e+00)
+; CHECK-NEXT: [[SHUFFLE:%.*]] = shufflevector <4 x float> [[X]], <4 x float> poison, <4 x i32> <i32 4, i32 1, i32 6, i32 3>
+; CHECK-NEXT: [[SEL:%.*]] = select <4 x i1> [[FCMP]], <4 x float> [[SHUFFLE]], <4 x float> <float poison, float 2.000000e+00, float poison, float 2.000000e+00>
+; CHECK-NEXT: ret <4 x float> [[SEL]]
+;
+ %fcmp = fcmp oeq <4 x float> %x, <float 2.0, float 2.0, float 2.0, float 2.0>
+ %shuffle = shufflevector <4 x float> %x, <4 x float> poison, <4 x i32> <i32 4, i32 1, i32 6, i32 3>
+ %sel = select <4 x i1> %fcmp, <4 x float> %shuffle, <4 x float> <float poison, float 2.0, float poison, float 2.0>
+ ret <4 x float> %sel
+}
+
+; The hexfloat constant is PI / 2.
+define float @select_fcmp_sin_nonrefinement(float %x) {
+; CHECK-LABEL: @select_fcmp_sin_nonrefinement(
+; CHECK-NEXT: [[FCMP:%.*]] = fcmp oeq float [[X:%.*]], 0x3FF921FB60000000
+; CHECK-NEXT: [[SIN:%.*]] = call float @llvm.sin.f32(float [[X]])
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[FCMP]], float 1.000000e+00, float [[SIN]]
+; CHECK-NEXT: ret float [[SEL]]
+;
+ %fcmp = fcmp oeq float %x, 0x3FF921FB60000000
+ %sin = call float @llvm.sin.f32(float %x)
+ %sel = select i1 %fcmp, float 1.0, float %sin
+ ret float %sel
+}
+
+; The hexfloat constant is PI / 2.
+define float @select_fcmp_sin(float %x) {
+; CHECK-LABEL: @select_fcmp_sin(
+; CHECK-NEXT: [[FCMP:%.*]] = fcmp oeq float [[X:%.*]], 0x3FF921FB60000000
+; CHECK-NEXT: [[SIN:%.*]] = call float @llvm.sin.f32(float [[X]])
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[FCMP]], float [[SIN]], float 1.000000e+00
+; CHECK-NEXT: ret float [[SEL]]
+;
+ %fcmp = fcmp oeq float %x, 0x3FF921FB60000000
+ %sin = call float @llvm.sin.f32(float %x)
+ %sel = select i1 %fcmp, float %sin, float 1.0
+ ret float %sel
+}
+
+; The hexfloat constant is PI.
+define float @select_fcmp_cos_nonrefinement(float %x) {
+; CHECK-LABEL: @select_fcmp_cos_nonrefinement(
+; CHECK-NEXT: [[FCMP:%.*]] = fcmp oeq float [[X:%.*]], 0x400921FB60000000
+; CHECK-NEXT: [[COS:%.*]] = call float @llvm.cos.f32(float [[X]])
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[FCMP]], float -1.000000e+00, float [[COS]]
+; CHECK-NEXT: ret float [[SEL]]
+;
+ %fcmp = fcmp oeq float %x, 0x400921FB60000000
+ %cos = call float @llvm.cos.f32(float %x)
+ %sel = select i1 %fcmp, float -1.0, float %cos
+ ret float %sel
+}
+
+; The hexfloat constant is PI.
+define float @select_fcmp_cos(float %x) {
+; CHECK-LABEL: @select_fcmp_cos(
+; CHECK-NEXT: [[FCMP:%.*]] = fcmp oeq float [[X:%.*]], 0x400921FB60000000
+; CHECK-NEXT: [[COS:%.*]] = call float @llvm.cos.f32(float [[X]])
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[FCMP]], float [[COS]], float -1.000000e+00
+; CHECK-NEXT: ret float [[SEL]]
+;
+ %fcmp = fcmp oeq float %x, 0x400921FB60000000
+ %cos = call float @llvm.cos.f32(float %x)
+ %sel = select i1 %fcmp, float %cos, float -1.0
+ ret float %sel
+}
+
+define i32 @select_fcmp_lrint(float %x) {
+; CHECK-LABEL: @select_fcmp_lrint(
+; CHECK-NEXT: [[FCMP:%.*]] = fcmp oeq float [[X:%.*]], 1.000000e+00
+; CHECK-NEXT: [[LRINT:%.*]] = call i32 @llvm.lrint.i32.f32(float [[X]])
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[FCMP]], i32 [[LRINT]], i32 1
+; CHECK-NEXT: ret i32 [[SEL]]
+;
+ %fcmp = fcmp oeq float %x, 1.0
+ %lrint = call i32 @llvm.lrint.i32.f32(float %x)
+ %sel = select i1 %fcmp, i32 %lrint, i32 1
+ ret i32 %sel
+}
>From 72f543c56724604d1bd2609ee4a8be4336281cb3 Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra <ramkumar.ramachandra at codasip.com>
Date: Tue, 5 Nov 2024 11:52:41 +0000
Subject: [PATCH 2/2] InstSimplify: support floating-point equivalences
Since cd16b07 (IR: introduce CmpInst::isEquivalence), there is now an
isEquivalence routine in CmpInst that we can use to determine
equivalence in simplifySelectWithICmpEq. Implement this, extending
the code from integer-equalities to integer and floating-point
equivalences.
---
llvm/lib/Analysis/InstructionSimplify.cpp | 88 ++++++++++++-------
.../InstSimplify/select-equivalence-fp.ll | 77 ++++------------
2 files changed, 74 insertions(+), 91 deletions(-)
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index daa468ac095c36..64e241162bf9e0 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -4466,13 +4466,15 @@ static Value *simplifyWithOpReplaced(Value *V, Value *Op, Value *RepOp,
} else
return nullptr;
}
- Constant *Res = ConstantFoldInstOperands(I, ConstOps, Q.DL, Q.TLI);
+ Constant *Res = ConstantFoldInstOperands(I, ConstOps, Q.DL, Q.TLI,
+ /*AllowNonDeterministic=*/false);
if (DropFlags && Res && I->hasPoisonGeneratingAnnotations())
DropFlags->push_back(I);
return Res;
}
- return ConstantFoldInstOperands(I, ConstOps, Q.DL, Q.TLI);
+ return ConstantFoldInstOperands(I, ConstOps, Q.DL, Q.TLI,
+ /*AllowNonDeterministic=*/false);
}
Value *llvm::simplifyWithOpReplaced(Value *V, Value *Op, Value *RepOp,
@@ -4616,11 +4618,11 @@ static Value *simplifySelectWithFakeICmpEq(Value *CmpLHS, Value *CmpRHS,
}
/// Try to simplify a select instruction when its condition operand is an
-/// integer equality comparison.
-static Value *simplifySelectWithICmpEq(Value *CmpLHS, Value *CmpRHS,
- Value *TrueVal, Value *FalseVal,
- const SimplifyQuery &Q,
- unsigned MaxRecurse) {
+/// integer equality or floating-point equivalence comparison.
+static Value *simplifySelectWithEquivalence(Value *CmpLHS, Value *CmpRHS,
+ Value *TrueVal, Value *FalseVal,
+ const SimplifyQuery &Q,
+ unsigned MaxRecurse) {
if (simplifyWithOpReplaced(FalseVal, CmpLHS, CmpRHS, Q.getWithoutUndef(),
/* AllowRefinement */ false,
/* DropFlags */ nullptr, MaxRecurse) == TrueVal)
@@ -4721,11 +4723,11 @@ static Value *simplifySelectWithICmpCond(Value *CondVal, Value *TrueVal,
// the arms of the select. See if substituting this value into the arm and
// simplifying the result yields the same value as the other arm.
if (Pred == ICmpInst::ICMP_EQ) {
- if (Value *V = simplifySelectWithICmpEq(CmpLHS, CmpRHS, TrueVal, FalseVal,
- Q, MaxRecurse))
+ if (Value *V = simplifySelectWithEquivalence(CmpLHS, CmpRHS, TrueVal,
+ FalseVal, Q, MaxRecurse))
return V;
- if (Value *V = simplifySelectWithICmpEq(CmpRHS, CmpLHS, TrueVal, FalseVal,
- Q, MaxRecurse))
+ if (Value *V = simplifySelectWithEquivalence(CmpRHS, CmpLHS, TrueVal,
+ FalseVal, Q, MaxRecurse))
return V;
Value *X;
@@ -4734,11 +4736,11 @@ static Value *simplifySelectWithICmpCond(Value *CondVal, Value *TrueVal,
if (match(CmpLHS, m_Or(m_Value(X), m_Value(Y))) &&
match(CmpRHS, m_Zero())) {
// (X | Y) == 0 implies X == 0 and Y == 0.
- if (Value *V = simplifySelectWithICmpEq(X, CmpRHS, TrueVal, FalseVal, Q,
- MaxRecurse))
+ if (Value *V = simplifySelectWithEquivalence(X, CmpRHS, TrueVal, FalseVal,
+ Q, MaxRecurse))
return V;
- if (Value *V = simplifySelectWithICmpEq(Y, CmpRHS, TrueVal, FalseVal, Q,
- MaxRecurse))
+ if (Value *V = simplifySelectWithEquivalence(Y, CmpRHS, TrueVal, FalseVal,
+ Q, MaxRecurse))
return V;
}
@@ -4746,11 +4748,11 @@ static Value *simplifySelectWithICmpCond(Value *CondVal, Value *TrueVal,
if (match(CmpLHS, m_And(m_Value(X), m_Value(Y))) &&
match(CmpRHS, m_AllOnes())) {
// (X & Y) == -1 implies X == -1 and Y == -1.
- if (Value *V = simplifySelectWithICmpEq(X, CmpRHS, TrueVal, FalseVal, Q,
- MaxRecurse))
+ if (Value *V = simplifySelectWithEquivalence(X, CmpRHS, TrueVal, FalseVal,
+ Q, MaxRecurse))
return V;
- if (Value *V = simplifySelectWithICmpEq(Y, CmpRHS, TrueVal, FalseVal, Q,
- MaxRecurse))
+ if (Value *V = simplifySelectWithEquivalence(Y, CmpRHS, TrueVal, FalseVal,
+ Q, MaxRecurse))
return V;
}
}
@@ -4761,27 +4763,51 @@ static Value *simplifySelectWithICmpCond(Value *CondVal, Value *TrueVal,
/// Try to simplify a select instruction when its condition operand is a
/// floating-point comparison.
static Value *simplifySelectWithFCmp(Value *Cond, Value *T, Value *F,
- const SimplifyQuery &Q) {
+ const SimplifyQuery &Q,
+ unsigned MaxRecurse) {
FCmpInst::Predicate Pred;
- if (!match(Cond, m_FCmp(Pred, m_Specific(T), m_Specific(F))) &&
- !match(Cond, m_FCmp(Pred, m_Specific(F), m_Specific(T))))
+ Value *CmpLHS, *CmpRHS;
+ if (!match(Cond, m_FCmp(Pred, m_Value(CmpLHS), m_Value(CmpRHS))))
+ return nullptr;
+ FCmpInst *I = cast<FCmpInst>(Cond);
+
+ bool IsEquiv = I->isEquivalence(),
+ IsInverseEquiv = I->isEquivalence(/*Invert=*/true);
+
+ if (IsInverseEquiv)
+ std::swap(T, F);
+
+ // Canonicalize CmpLHS to be T, and CmpRHS to be F, if they're swapped.
+ if (CmpLHS == F && CmpRHS == T)
+ std::swap(CmpLHS, CmpRHS);
+
+ // This transforms is safe if at least one operand is known to not be zero.
+ // Otherwise, the select can change the sign of a zero operand.
+ if (IsEquiv || IsInverseEquiv) {
+ if (Value *V =
+ simplifySelectWithEquivalence(CmpLHS, CmpRHS, T, F, Q, MaxRecurse))
+ return V;
+ if (Value *V =
+ simplifySelectWithEquivalence(CmpRHS, CmpLHS, T, F, Q, MaxRecurse))
+ return V;
+
+ // (T == F) ? T : F --> F
+ // (T != F) ? F : T --> F
+ return CmpLHS == T && CmpRHS == F ? F : nullptr;
+ }
+
+ if (CmpLHS != T || CmpRHS != F)
return nullptr;
- // This transform is safe if we do not have (do not care about) -0.0 or if
- // at least one operand is known to not be -0.0. Otherwise, the select can
- // change the sign of a zero operand.
+ // This transform is also safe if we do not have (do not care about) -0.0.
bool HasNoSignedZeros =
Q.CxtI && isa<FPMathOperator>(Q.CxtI) && Q.CxtI->hasNoSignedZeros();
- const APFloat *C;
- if (HasNoSignedZeros || (match(T, m_APFloat(C)) && C->isNonZero()) ||
- (match(F, m_APFloat(C)) && C->isNonZero())) {
+ if (HasNoSignedZeros) {
// (T == F) ? T : F --> F
- // (F == T) ? T : F --> F
if (Pred == FCmpInst::FCMP_OEQ)
return F;
// (T != F) ? T : F --> T
- // (F != T) ? T : F --> T
if (Pred == FCmpInst::FCMP_UNE)
return T;
}
@@ -4955,7 +4981,7 @@ static Value *simplifySelectInst(Value *Cond, Value *TrueVal, Value *FalseVal,
simplifySelectWithICmpCond(Cond, TrueVal, FalseVal, Q, MaxRecurse))
return V;
- if (Value *V = simplifySelectWithFCmp(Cond, TrueVal, FalseVal, Q))
+ if (Value *V = simplifySelectWithFCmp(Cond, TrueVal, FalseVal, Q, MaxRecurse))
return V;
if (Value *V = foldSelectWithBinaryOp(Cond, TrueVal, FalseVal))
diff --git a/llvm/test/Transforms/InstSimplify/select-equivalence-fp.ll b/llvm/test/Transforms/InstSimplify/select-equivalence-fp.ll
index bad6a532bd4db8..8af751d0a4246d 100644
--- a/llvm/test/Transforms/InstSimplify/select-equivalence-fp.ll
+++ b/llvm/test/Transforms/InstSimplify/select-equivalence-fp.ll
@@ -3,10 +3,7 @@
define float @select_fcmp_fsub_oeq(float %x) {
; CHECK-LABEL: @select_fcmp_fsub_oeq(
-; CHECK-NEXT: [[FCMP:%.*]] = fcmp oeq float [[X:%.*]], 2.000000e+00
-; CHECK-NEXT: [[FADD:%.*]] = fsub float [[X]], 2.000000e+00
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[FCMP]], float [[FADD]], float 0.000000e+00
-; CHECK-NEXT: ret float [[SEL]]
+; CHECK-NEXT: ret float 0.000000e+00
;
%fcmp = fcmp oeq float %x, 2.0
%fadd = fsub float %x, 2.0
@@ -42,10 +39,7 @@ define float @select_fcmp_fsub_ueq(float %x) {
define float @select_fcmp_fsub_ueq_nnan(float %x) {
; CHECK-LABEL: @select_fcmp_fsub_ueq_nnan(
-; CHECK-NEXT: [[FCMP:%.*]] = fcmp nnan ueq float [[X:%.*]], 2.000000e+00
-; CHECK-NEXT: [[FADD:%.*]] = fsub float [[X]], 2.000000e+00
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[FCMP]], float [[FADD]], float 0.000000e+00
-; CHECK-NEXT: ret float [[SEL]]
+; CHECK-NEXT: ret float 0.000000e+00
;
%fcmp = fcmp nnan ueq float %x, 2.0
%fadd = fsub float %x, 2.0
@@ -55,10 +49,7 @@ define float @select_fcmp_fsub_ueq_nnan(float %x) {
define float @select_fcmp_fsub_une(float %x) {
; CHECK-LABEL: @select_fcmp_fsub_une(
-; CHECK-NEXT: [[FCMP:%.*]] = fcmp une float [[X:%.*]], 2.000000e+00
-; CHECK-NEXT: [[FADD:%.*]] = fsub float [[X]], 2.000000e+00
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[FCMP]], float 0.000000e+00, float [[FADD]]
-; CHECK-NEXT: ret float [[SEL]]
+; CHECK-NEXT: ret float 0.000000e+00
;
%fcmp = fcmp une float %x, 2.0
%fadd = fsub float %x, 2.0
@@ -94,10 +85,7 @@ define float @select_fcmp_fsub_one(float %x) {
define float @select_fcmp_fsub_one_nnan(float %x) {
; CHECK-LABEL: @select_fcmp_fsub_one_nnan(
-; CHECK-NEXT: [[FCMP:%.*]] = fcmp nnan one float [[X:%.*]], 2.000000e+00
-; CHECK-NEXT: [[FADD:%.*]] = fsub float [[X]], 2.000000e+00
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[FCMP]], float 0.000000e+00, float [[FADD]]
-; CHECK-NEXT: ret float [[SEL]]
+; CHECK-NEXT: ret float 0.000000e+00
;
%fcmp = fcmp nnan one float %x, 2.0
%fadd = fsub float %x, 2.0
@@ -107,10 +95,7 @@ define float @select_fcmp_fsub_one_nnan(float %x) {
define float @select_fcmp_fadd(float %x) {
; CHECK-LABEL: @select_fcmp_fadd(
-; CHECK-NEXT: [[FCMP:%.*]] = fcmp oeq float [[X:%.*]], 2.000000e+00
-; CHECK-NEXT: [[FADD:%.*]] = fadd float [[X]], 2.000000e+00
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[FCMP]], float [[FADD]], float 4.000000e+00
-; CHECK-NEXT: ret float [[SEL]]
+; CHECK-NEXT: ret float 4.000000e+00
;
%fcmp = fcmp oeq float %x, 2.0
%fadd = fadd float %x, 2.0
@@ -120,10 +105,7 @@ define float @select_fcmp_fadd(float %x) {
define <2 x float> @select_fcmp_fadd_vec(<2 x float> %x) {
; CHECK-LABEL: @select_fcmp_fadd_vec(
-; CHECK-NEXT: [[FCMP:%.*]] = fcmp oeq <2 x float> [[X:%.*]], splat (float 2.000000e+00)
-; CHECK-NEXT: [[FADD:%.*]] = fadd <2 x float> [[X]], splat (float 2.000000e+00)
-; CHECK-NEXT: [[SEL:%.*]] = select <2 x i1> [[FCMP]], <2 x float> [[FADD]], <2 x float> splat (float 4.000000e+00)
-; CHECK-NEXT: ret <2 x float> [[SEL]]
+; CHECK-NEXT: ret <2 x float> splat (float 4.000000e+00)
;
%fcmp = fcmp oeq <2 x float> %x, <float 2.0, float 2.0>
%fadd = fadd <2 x float> %x, <float 2.0, float 2.0>
@@ -134,10 +116,8 @@ define <2 x float> @select_fcmp_fadd_vec(<2 x float> %x) {
define float @select_fcmp_fmul_nonrefinement(float %x, float %y) {
; CHECK-LABEL: @select_fcmp_fmul_nonrefinement(
-; 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]]
+; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: ret float [[FMUL]]
;
%fcmp = fcmp oeq float %x, 1.0
%fmul = fmul float %y, %x
@@ -147,10 +127,7 @@ define float @select_fcmp_fmul_nonrefinement(float %x, float %y) {
define float @select_fcmp_fmul(float %x) {
; CHECK-LABEL: @select_fcmp_fmul(
-; CHECK-NEXT: [[FCMP:%.*]] = fcmp oeq float [[X:%.*]], 2.000000e+00
-; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[X]], 2.000000e+00
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[FCMP]], float [[FMUL]], float 4.000000e+00
-; CHECK-NEXT: ret float [[SEL]]
+; CHECK-NEXT: ret float 4.000000e+00
;
%fcmp = fcmp oeq float %x, 2.0
%fmul = fmul float %x, 2.0
@@ -160,10 +137,8 @@ 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: [[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]]
+; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: ret float [[FDIV]]
;
%fcmp = fcmp oeq float %x, 1.0
%fdiv = fdiv float %y, %x
@@ -173,10 +148,7 @@ define float @select_fcmp_fdiv_nonrefinement(float %x, float %y) {
define float @select_fcmp_fdiv(float %x) {
; CHECK-LABEL: @select_fcmp_fdiv(
-; CHECK-NEXT: [[FCMP:%.*]] = fcmp oeq float [[X:%.*]], 2.000000e+00
-; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[X]], 2.000000e+00
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[FCMP]], float [[FDIV]], float 1.000000e+00
-; CHECK-NEXT: ret float [[SEL]]
+; CHECK-NEXT: ret float 1.000000e+00
;
%fcmp = fcmp oeq float %x, 2.0
%fdiv = fdiv float %x, 2.0
@@ -186,10 +158,7 @@ define float @select_fcmp_fdiv(float %x) {
define float @select_fcmp_frem(float %x) {
; CHECK-LABEL: @select_fcmp_frem(
-; CHECK-NEXT: [[FCMP:%.*]] = fcmp oeq float [[X:%.*]], 3.000000e+00
-; CHECK-NEXT: [[FREM:%.*]] = frem float [[X]], 2.000000e+00
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[FCMP]], float [[FREM]], float 1.000000e+00
-; CHECK-NEXT: ret float [[SEL]]
+; CHECK-NEXT: ret float 1.000000e+00
;
%fcmp = fcmp oeq float %x, 3.0
%frem = frem float %x, 2.0
@@ -199,10 +168,7 @@ define float @select_fcmp_frem(float %x) {
define <2 x float> @select_fcmp_insertelement(<2 x float> %x) {
; CHECK-LABEL: @select_fcmp_insertelement(
-; CHECK-NEXT: [[FCMP:%.*]] = fcmp oeq <2 x float> [[X:%.*]], splat (float 2.000000e+00)
-; CHECK-NEXT: [[INSERT:%.*]] = insertelement <2 x float> [[X]], float 4.000000e+00, i64 0
-; CHECK-NEXT: [[SEL:%.*]] = select <2 x i1> [[FCMP]], <2 x float> [[INSERT]], <2 x float> <float 4.000000e+00, float 2.000000e+00>
-; CHECK-NEXT: ret <2 x float> [[SEL]]
+; CHECK-NEXT: ret <2 x float> <float 4.000000e+00, float 2.000000e+00>
;
%fcmp = fcmp oeq <2 x float> %x, <float 2.0, float 2.0>
%insert = insertelement <2 x float> %x, float 4.0, i64 0
@@ -212,10 +178,7 @@ define <2 x float> @select_fcmp_insertelement(<2 x float> %x) {
define <4 x float> @select_fcmp_shufflevector_select(<4 x float> %x) {
; CHECK-LABEL: @select_fcmp_shufflevector_select(
-; CHECK-NEXT: [[FCMP:%.*]] = fcmp oeq <4 x float> [[X:%.*]], splat (float 2.000000e+00)
-; CHECK-NEXT: [[SHUFFLE:%.*]] = shufflevector <4 x float> [[X]], <4 x float> poison, <4 x i32> <i32 4, i32 1, i32 6, i32 3>
-; CHECK-NEXT: [[SEL:%.*]] = select <4 x i1> [[FCMP]], <4 x float> [[SHUFFLE]], <4 x float> <float poison, float 2.000000e+00, float poison, float 2.000000e+00>
-; CHECK-NEXT: ret <4 x float> [[SEL]]
+; CHECK-NEXT: ret <4 x float> <float poison, float 2.000000e+00, float poison, float 2.000000e+00>
;
%fcmp = fcmp oeq <4 x float> %x, <float 2.0, float 2.0, float 2.0, float 2.0>
%shuffle = shufflevector <4 x float> %x, <4 x float> poison, <4 x i32> <i32 4, i32 1, i32 6, i32 3>
@@ -240,10 +203,7 @@ define float @select_fcmp_sin_nonrefinement(float %x) {
; The hexfloat constant is PI / 2.
define float @select_fcmp_sin(float %x) {
; CHECK-LABEL: @select_fcmp_sin(
-; CHECK-NEXT: [[FCMP:%.*]] = fcmp oeq float [[X:%.*]], 0x3FF921FB60000000
-; CHECK-NEXT: [[SIN:%.*]] = call float @llvm.sin.f32(float [[X]])
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[FCMP]], float [[SIN]], float 1.000000e+00
-; CHECK-NEXT: ret float [[SEL]]
+; CHECK-NEXT: ret float 1.000000e+00
;
%fcmp = fcmp oeq float %x, 0x3FF921FB60000000
%sin = call float @llvm.sin.f32(float %x)
@@ -268,10 +228,7 @@ define float @select_fcmp_cos_nonrefinement(float %x) {
; The hexfloat constant is PI.
define float @select_fcmp_cos(float %x) {
; CHECK-LABEL: @select_fcmp_cos(
-; CHECK-NEXT: [[FCMP:%.*]] = fcmp oeq float [[X:%.*]], 0x400921FB60000000
-; CHECK-NEXT: [[COS:%.*]] = call float @llvm.cos.f32(float [[X]])
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[FCMP]], float [[COS]], float -1.000000e+00
-; CHECK-NEXT: ret float [[SEL]]
+; CHECK-NEXT: ret float -1.000000e+00
;
%fcmp = fcmp oeq float %x, 0x400921FB60000000
%cos = call float @llvm.cos.f32(float %x)
More information about the llvm-commits
mailing list