From 455ef0346c1e5481283e5ed6ae4e5f9145f586bc Mon Sep 17 00:00:00 2001 From: Ramkumar Ramachandra Date: Wed, 6 Nov 2024 11:39:26 +0000 Subject: [PATCH 1/4] 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 0000000000000..bad6a532bd4db --- /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, + %fadd = fadd <2 x float> %x, + %sel = select <2 x i1> %fcmp, <2 x float> %fadd, <2 x float> + 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> +; CHECK-NEXT: ret <2 x float> [[SEL]] +; + %fcmp = fcmp oeq <2 x float> %x, + %insert = insertelement <2 x float> %x, float 4.0, i64 0 + %sel = select <2 x i1> %fcmp, <2 x float> %insert, <2 x float> + 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> +; CHECK-NEXT: [[SEL:%.*]] = select <4 x i1> [[FCMP]], <4 x float> [[SHUFFLE]], <4 x float> +; CHECK-NEXT: ret <4 x float> [[SEL]] +; + %fcmp = fcmp oeq <4 x float> %x, + %shuffle = shufflevector <4 x float> %x, <4 x float> poison, <4 x i32> + %sel = select <4 x i1> %fcmp, <4 x float> %shuffle, <4 x float> + 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 Date: Tue, 5 Nov 2024 11:52:41 +0000 Subject: [PATCH 2/4] 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 daa468ac095c3..64e241162bf9e 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(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(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 bad6a532bd4db..8af751d0a4246 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, %fadd = fadd <2 x float> %x, @@ -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> -; CHECK-NEXT: ret <2 x float> [[SEL]] +; CHECK-NEXT: ret <2 x float> ; %fcmp = fcmp oeq <2 x float> %x, %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> -; CHECK-NEXT: [[SEL:%.*]] = select <4 x i1> [[FCMP]], <4 x float> [[SHUFFLE]], <4 x float> -; CHECK-NEXT: ret <4 x float> [[SEL]] +; CHECK-NEXT: ret <4 x float> ; %fcmp = fcmp oeq <4 x float> %x, %shuffle = shufflevector <4 x float> %x, <4 x float> poison, <4 x i32> @@ -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) From e0244b24daa3ac940fd53cab6ea742a9b557a512 Mon Sep 17 00:00:00 2001 From: Ramkumar Ramachandra Date: Mon, 11 Nov 2024 14:24:59 +0000 Subject: [PATCH 3/4] InstSimplify: fix thinko; address review --- llvm/lib/Analysis/InstructionSimplify.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp index 64e241162bf9e..b1dba3f502896 100644 --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -4790,10 +4790,6 @@ static Value *simplifySelectWithFCmp(Value *Cond, Value *T, Value *F, 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) From 78c076d01bb886c8d9c3c4c290c26365fe177e26 Mon Sep 17 00:00:00 2001 From: Ramkumar Ramachandra Date: Mon, 11 Nov 2024 15:02:54 +0000 Subject: [PATCH 4/4] InstSimplify: address review --- llvm/lib/Analysis/InstructionSimplify.cpp | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp index b1dba3f502896..4a2750fcd1d41 100644 --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -4771,19 +4771,16 @@ static Value *simplifySelectWithFCmp(Value *Cond, Value *T, Value *F, return nullptr; FCmpInst *I = cast(Cond); - bool IsEquiv = I->isEquivalence(), - IsInverseEquiv = I->isEquivalence(/*Invert=*/true); - - if (IsInverseEquiv) + bool IsEquiv = I->isEquivalence(); + if (I->isEquivalence(/*Invert=*/true)) { 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); + Pred = FCmpInst::getInversePredicate(Pred); + IsEquiv = true; + } // 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 (IsEquiv) { if (Value *V = simplifySelectWithEquivalence(CmpLHS, CmpRHS, T, F, Q, MaxRecurse)) return V; @@ -4792,13 +4789,15 @@ static Value *simplifySelectWithFCmp(Value *Cond, Value *T, Value *F, return V; } + // Canonicalize CmpLHS to be T, and CmpRHS to be F, if they're swapped. + if (CmpLHS == F && CmpRHS == T) + std::swap(CmpLHS, CmpRHS); + if (CmpLHS != T || CmpRHS != F) return nullptr; // This transform is also safe if we do not have (do not care about) -0.0. - bool HasNoSignedZeros = - Q.CxtI && isa(Q.CxtI) && Q.CxtI->hasNoSignedZeros(); - if (HasNoSignedZeros) { + if (Q.CxtI && isa(Q.CxtI) && Q.CxtI->hasNoSignedZeros()) { // (T == F) ? T : F --> F if (Pred == FCmpInst::FCMP_OEQ) return F;