From f475b6d0f14758f93d23b0905491bdc531826456 Mon Sep 17 00:00:00 2001 From: Yingwei Zheng Date: Wed, 7 Feb 2024 14:07:42 +0800 Subject: [PATCH 1/5] [ValueTracking] Add pre-commit tests. NFC. --- .../InstCombine/fpclass-from-dom-cond.ll | 213 ++++++++++++++++++ 1 file changed, 213 insertions(+) create mode 100644 llvm/test/Transforms/InstCombine/fpclass-from-dom-cond.ll diff --git a/llvm/test/Transforms/InstCombine/fpclass-from-dom-cond.ll b/llvm/test/Transforms/InstCombine/fpclass-from-dom-cond.ll new file mode 100644 index 0000000000000..e74ec2c3ec9eb --- /dev/null +++ b/llvm/test/Transforms/InstCombine/fpclass-from-dom-cond.ll @@ -0,0 +1,213 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4 +; RUN: opt -S -passes=instcombine < %s | FileCheck %s + +define i1 @test1(float %x) { +; CHECK-LABEL: define i1 @test1( +; CHECK-SAME: float [[X:%.*]]) { +; CHECK-NEXT: entry: +; CHECK-NEXT: [[COND:%.*]] = fcmp ueq float [[X]], 0.000000e+00 +; CHECK-NEXT: br i1 [[COND]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then: +; CHECK-NEXT: ret i1 false +; CHECK: if.else: +; CHECK-NEXT: [[RET:%.*]] = call i1 @llvm.is.fpclass.f32(float [[X]], i32 783) +; CHECK-NEXT: ret i1 [[RET]] +; +entry: + %cond = fcmp ueq float %x, 0.000000e+00 + br i1 %cond, label %if.then, label %if.else + +if.then: + ret i1 false + +if.else: + %ret = call i1 @llvm.is.fpclass.f32(float %x, i32 783) + ret i1 %ret +} + +define i1 @test2(double %x) { +; CHECK-LABEL: define i1 @test2( +; CHECK-SAME: double [[X:%.*]]) { +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CMP:%.*]] = fcmp olt double [[X]], 0x3EB0C6F7A0000000 +; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +; CHECK: if.then: +; CHECK-NEXT: ret i1 false +; CHECK: if.end: +; CHECK-NEXT: [[CMP_I:%.*]] = fcmp oeq double [[X]], 0.000000e+00 +; CHECK-NEXT: ret i1 [[CMP_I]] +; +entry: + %cmp = fcmp olt double %x, 0x3EB0C6F7A0000000 + br i1 %cmp, label %if.then, label %if.end +if.then: + ret i1 false +if.end: + %cmp.i = fcmp oeq double %x, 0.000000e+00 + ret i1 %cmp.i +} + +define i1 @test3(float %x) { +; CHECK-LABEL: define i1 @test3( +; CHECK-SAME: float [[X:%.*]]) { +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CMP:%.*]] = fcmp ogt float [[X]], 3.000000e+00 +; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then: +; CHECK-NEXT: [[ABS:%.*]] = call float @llvm.fabs.f32(float [[X]]) +; CHECK-NEXT: [[RET:%.*]] = fcmp oeq float [[ABS]], 0x7FF0000000000000 +; CHECK-NEXT: ret i1 [[RET]] +; CHECK: if.else: +; CHECK-NEXT: ret i1 false +; +entry: + %cmp = fcmp ogt float %x, 3.000000e+00 + br i1 %cmp, label %if.then, label %if.else +if.then: + %abs = call float @llvm.fabs.f32(float %x) + %ret = fcmp oeq float %abs, 0x7FF0000000000000 + ret i1 %ret +if.else: + ret i1 false +} + +define float @test4(float %x) { +; CHECK-LABEL: define float @test4( +; CHECK-SAME: float [[X:%.*]]) { +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CMP:%.*]] = fcmp olt float [[X]], 0x3EB0C6F7A0000000 +; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +; CHECK: if.then: +; CHECK-NEXT: ret float 1.000000e+00 +; CHECK: if.end: +; CHECK-NEXT: [[CMP_I:%.*]] = fcmp oeq float [[X]], 0.000000e+00 +; CHECK-NEXT: [[DIV:%.*]] = fdiv float 1.000000e+00, [[X]] +; CHECK-NEXT: [[RET:%.*]] = select i1 [[CMP_I]], float 1.000000e+00, float [[DIV]] +; CHECK-NEXT: ret float [[RET]] +; +entry: + %cmp = fcmp olt float %x, 0x3EB0C6F7A0000000 + br i1 %cmp, label %if.then, label %if.end + +if.then: + ret float 1.0 + +if.end: + %cmp.i = fcmp oeq float %x, 0.000000e+00 + %div = fdiv float 1.000000e+00, %x + %ret = select i1 %cmp.i, float 1.000000e+00, float %div + ret float %ret +} + +define i1 @test5(double %x, i1 %cond) { +; CHECK-LABEL: define i1 @test5( +; CHECK-SAME: double [[X:%.*]], i1 [[COND:%.*]]) { +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[COND]], label [[IF:%.*]], label [[EXIT:%.*]] +; CHECK: if: +; CHECK-NEXT: [[CMP:%.*]] = fcmp uno double [[X]], 0.000000e+00 +; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +; CHECK: if.then: +; CHECK-NEXT: ret i1 false +; CHECK: if.end: +; CHECK-NEXT: br label [[EXIT]] +; CHECK: exit: +; CHECK-NEXT: [[Y:%.*]] = phi double [ -1.000000e+00, [[ENTRY:%.*]] ], [ [[X]], [[IF_END]] ] +; CHECK-NEXT: [[RET:%.*]] = tail call i1 @llvm.is.fpclass.f64(double [[Y]], i32 411) +; CHECK-NEXT: ret i1 [[RET]] +; +entry: + br i1 %cond, label %if, label %exit +if: + %cmp = fcmp uno double %x, 0.000000e+00 + br i1 %cmp, label %if.then, label %if.end +if.then: + ret i1 false +if.end: + br label %exit +exit: + %y = phi double [ -1.000000e+00, %entry ], [ %x, %if.end ] + %ret = tail call i1 @llvm.is.fpclass.f64(double %y, i32 411) + ret i1 %ret +} + +define i1 @test6(double %x) { +; CHECK-LABEL: define i1 @test6( +; CHECK-SAME: double [[X:%.*]]) { +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CMP:%.*]] = fcmp ogt double [[X]], 0.000000e+00 +; CHECK-NEXT: br i1 [[CMP]], label [[LAND_RHS:%.*]], label [[LAND_END:%.*]] +; CHECK: land.rhs: +; CHECK-NEXT: [[ABS:%.*]] = tail call double @llvm.fabs.f64(double [[X]]) +; CHECK-NEXT: [[AND_I:%.*]] = bitcast double [[ABS]] to i64 +; CHECK-NEXT: [[CMP_I:%.*]] = icmp eq i64 [[AND_I]], 9218868437227405312 +; CHECK-NEXT: br label [[LAND_END]] +; CHECK: land.end: +; CHECK-NEXT: [[RET:%.*]] = phi i1 [ false, [[ENTRY:%.*]] ], [ [[CMP_I]], [[LAND_RHS]] ] +; CHECK-NEXT: ret i1 [[RET]] +; +entry: + %cmp = fcmp ogt double %x, 0.000000e+00 + br i1 %cmp, label %land.rhs, label %land.end + +land.rhs: + %abs = tail call double @llvm.fabs.f64(double %x) + %and.i = bitcast double %abs to i64 + %cmp.i = icmp eq i64 %and.i, 9218868437227405312 + br label %land.end + +land.end: + %ret = phi i1 [ false, %entry ], [ %cmp.i, %land.rhs ] + ret i1 %ret +} + +define i1 @test7(float %x) { +; CHECK-LABEL: define i1 @test7( +; CHECK-SAME: float [[X:%.*]]) { +; CHECK-NEXT: [[COND:%.*]] = call i1 @llvm.is.fpclass.f32(float [[X]], i32 345) +; CHECK-NEXT: br i1 [[COND]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then: +; CHECK-NEXT: [[RET1:%.*]] = call i1 @llvm.is.fpclass.f32(float [[X]], i32 456) +; CHECK-NEXT: ret i1 [[RET1]] +; CHECK: if.else: +; CHECK-NEXT: [[RET2:%.*]] = call i1 @llvm.is.fpclass.f32(float [[X]], i32 456) +; CHECK-NEXT: ret i1 [[RET2]] +; + %cond = call i1 @llvm.is.fpclass.f32(float %x, i32 345) + br i1 %cond, label %if.then, label %if.else +if.then: + %ret1 = call i1 @llvm.is.fpclass.f32(float %x, i32 456) + ret i1 %ret1 +if.else: + %ret2 = call i1 @llvm.is.fpclass.f32(float %x, i32 456) + ret i1 %ret2 +} + +define i1 @test1_no_dominating(float %x, i1 %c) { +; CHECK-LABEL: define i1 @test1_no_dominating( +; CHECK-SAME: float [[X:%.*]], i1 [[C:%.*]]) { +; CHECK-NEXT: entry0: +; CHECK-NEXT: br i1 [[C]], label [[ENTRY:%.*]], label [[IF_ELSE:%.*]] +; CHECK: entry: +; CHECK-NEXT: [[COND:%.*]] = fcmp ueq float [[X]], 0.000000e+00 +; CHECK-NEXT: br i1 [[COND]], label [[IF_THEN:%.*]], label [[IF_ELSE]] +; CHECK: if.then: +; CHECK-NEXT: ret i1 false +; CHECK: if.else: +; CHECK-NEXT: [[RET:%.*]] = call i1 @llvm.is.fpclass.f32(float [[X]], i32 783) +; CHECK-NEXT: ret i1 [[RET]] +; +entry0: + br i1 %c, label %entry, label %if.else + +entry: + %cond = fcmp ueq float %x, 0.000000e+00 + br i1 %cond, label %if.then, label %if.else + +if.then: + ret i1 false + +if.else: + %ret = call i1 @llvm.is.fpclass.f32(float %x, i32 783) + ret i1 %ret +} From 9fc28b7fd1954f81a95ec382b1ce9d36e2a12335 Mon Sep 17 00:00:00 2001 From: Yingwei Zheng Date: Wed, 7 Feb 2024 14:09:58 +0800 Subject: [PATCH 2/5] [ValueTracking] Compute known FPClass from dominating condition --- llvm/lib/Analysis/DomConditionCache.cpp | 5 + llvm/lib/Analysis/ValueTracking.cpp | 94 +++++++++++++------ .../InstCombine/fpclass-from-dom-cond.ll | 21 ++--- 3 files changed, 80 insertions(+), 40 deletions(-) diff --git a/llvm/lib/Analysis/DomConditionCache.cpp b/llvm/lib/Analysis/DomConditionCache.cpp index 3dad0c2e07133..f1d2f4b5d8c0a 100644 --- a/llvm/lib/Analysis/DomConditionCache.cpp +++ b/llvm/lib/Analysis/DomConditionCache.cpp @@ -69,6 +69,11 @@ static void findAffectedValues(Value *Cond, } } } + // Handle patterns that computeKnownFPClass() support. + if (match(Cond, m_FCmp(Pred, m_Value(A), m_Constant()))) + AddAffected(A); + if (match(Cond, m_Intrinsic(m_Value(A), m_Constant()))) + AddAffected(A); } void DomConditionCache::registerBranch(BranchInst *BI) { diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index 0e40a02fd4de6..f84254f212d83 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -4225,9 +4225,56 @@ llvm::fcmpImpliesClass(CmpInst::Predicate Pred, const Function &F, Value *LHS, return fcmpImpliesClass(Pred, F, LHS, *ConstRHS, LookThroughSrc); } -static FPClassTest computeKnownFPClassFromAssumes(const Value *V, - const SimplifyQuery &Q) { - FPClassTest KnownFromAssume = fcAllFlags; +static void computeKnownFPClassFromCond(const Value *V, Value *Cond, + bool CondIsTrue, + const Instruction *CxtI, + KnownFPClass &KnownFromContext) { + CmpInst::Predicate Pred; + Value *LHS; + Value *RHS; + uint64_t ClassVal = 0; + // TODO: handle sign-bit check idiom + if (match(Cond, m_FCmp(Pred, m_Value(LHS), m_Value(RHS)))) { + const APFloat *CRHS; + if (match(RHS, m_APFloat(CRHS))) { + auto [CmpVal, MaskIfTrue, MaskIfFalse] = fcmpImpliesClass( + Pred, *CxtI->getParent()->getParent(), LHS, *CRHS, LHS != V); + if (CmpVal == V) + KnownFromContext.knownNot(~(CondIsTrue ? MaskIfTrue : MaskIfFalse)); + } + } else if (match(Cond, m_Intrinsic( + m_Value(LHS), m_ConstantInt(ClassVal)))) { + FPClassTest Mask = static_cast(ClassVal); + KnownFromContext.knownNot(CondIsTrue ? ~Mask : Mask); + } +} + +static KnownFPClass computeKnownFPClassFromContext(const Value *V, + const SimplifyQuery &Q) { + KnownFPClass KnownFromContext; + + if (!Q.CxtI) + return KnownFromContext; + + if (Q.DC && Q.DT) { + // Handle dominating conditions. + for (BranchInst *BI : Q.DC->conditionsFor(V)) { + Value *Cond = BI->getCondition(); + + BasicBlockEdge Edge0(BI->getParent(), BI->getSuccessor(0)); + if (Q.DT->dominates(Edge0, Q.CxtI->getParent())) + computeKnownFPClassFromCond(V, Cond, /*CondIsTrue=*/true, Q.CxtI, + KnownFromContext); + + BasicBlockEdge Edge1(BI->getParent(), BI->getSuccessor(1)); + if (Q.DT->dominates(Edge1, Q.CxtI->getParent())) + computeKnownFPClassFromCond(V, Cond, /*CondIsTrue=*/false, Q.CxtI, + KnownFromContext); + } + } + + if (!Q.AC) + return KnownFromContext; // Try to restrict the floating-point classes based on information from // assumptions. @@ -4245,25 +4292,11 @@ static FPClassTest computeKnownFPClassFromAssumes(const Value *V, if (!isValidAssumeForContext(I, Q.CxtI, Q.DT)) continue; - CmpInst::Predicate Pred; - Value *LHS, *RHS; - uint64_t ClassVal = 0; - if (match(I->getArgOperand(0), m_FCmp(Pred, m_Value(LHS), m_Value(RHS)))) { - const APFloat *CRHS; - if (match(RHS, m_APFloat(CRHS))) { - auto [CmpVal, MaskIfTrue, MaskIfFalse] = - fcmpImpliesClass(Pred, *F, LHS, *CRHS, LHS != V); - if (CmpVal == V) - KnownFromAssume &= MaskIfTrue; - } - } else if (match(I->getArgOperand(0), - m_Intrinsic( - m_Value(LHS), m_ConstantInt(ClassVal)))) { - KnownFromAssume &= static_cast(ClassVal); - } + computeKnownFPClassFromCond(V, I->getArgOperand(0), /*CondIsTrue=*/true, + Q.CxtI, KnownFromContext); } - return KnownFromAssume; + return KnownFromContext; } void computeKnownFPClass(const Value *V, const APInt &DemandedElts, @@ -4371,10 +4404,8 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts, KnownNotFromFlags |= fcInf; } - if (Q.AC) { - FPClassTest AssumedClasses = computeKnownFPClassFromAssumes(V, Q); - KnownNotFromFlags |= ~AssumedClasses; - } + KnownFPClass AssumedClasses = computeKnownFPClassFromContext(V, Q); + KnownNotFromFlags |= ~AssumedClasses.KnownFPClasses; // We no longer need to find out about these bits from inputs if we can // assume this from flags/attributes. @@ -4382,6 +4413,12 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts, auto ClearClassesFromFlags = make_scope_exit([=, &Known] { Known.knownNot(KnownNotFromFlags); + if (!Known.SignBit && AssumedClasses.SignBit) { + if (*AssumedClasses.SignBit) + Known.signBitMustBeOne(); + else + Known.signBitMustBeZero(); + } }); if (!Op) @@ -5283,7 +5320,8 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts, bool First = true; - for (Value *IncValue : P->incoming_values()) { + for (const Use &U : P->operands()) { + Value *IncValue = U.get(); // Skip direct self references. if (IncValue == P) continue; @@ -5292,8 +5330,10 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts, // Recurse, but cap the recursion to two levels, because we don't want // to waste time spinning around in loops. We need at least depth 2 to // detect known sign bits. - computeKnownFPClass(IncValue, DemandedElts, InterestedClasses, KnownSrc, - PhiRecursionLimit, Q); + computeKnownFPClass( + IncValue, DemandedElts, InterestedClasses, KnownSrc, + PhiRecursionLimit, + Q.getWithInstruction(P->getIncomingBlock(U)->getTerminator())); if (First) { Known = KnownSrc; diff --git a/llvm/test/Transforms/InstCombine/fpclass-from-dom-cond.ll b/llvm/test/Transforms/InstCombine/fpclass-from-dom-cond.ll index e74ec2c3ec9eb..48c6e91057094 100644 --- a/llvm/test/Transforms/InstCombine/fpclass-from-dom-cond.ll +++ b/llvm/test/Transforms/InstCombine/fpclass-from-dom-cond.ll @@ -10,7 +10,7 @@ define i1 @test1(float %x) { ; CHECK: if.then: ; CHECK-NEXT: ret i1 false ; CHECK: if.else: -; CHECK-NEXT: [[RET:%.*]] = call i1 @llvm.is.fpclass.f32(float [[X]], i32 783) +; CHECK-NEXT: [[RET:%.*]] = call i1 @llvm.is.fpclass.f32(float [[X]], i32 780) ; CHECK-NEXT: ret i1 [[RET]] ; entry: @@ -34,8 +34,7 @@ define i1 @test2(double %x) { ; CHECK: if.then: ; CHECK-NEXT: ret i1 false ; CHECK: if.end: -; CHECK-NEXT: [[CMP_I:%.*]] = fcmp oeq double [[X]], 0.000000e+00 -; CHECK-NEXT: ret i1 [[CMP_I]] +; CHECK-NEXT: ret i1 false ; entry: %cmp = fcmp olt double %x, 0x3EB0C6F7A0000000 @@ -54,8 +53,7 @@ define i1 @test3(float %x) { ; CHECK-NEXT: [[CMP:%.*]] = fcmp ogt float [[X]], 3.000000e+00 ; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] ; CHECK: if.then: -; CHECK-NEXT: [[ABS:%.*]] = call float @llvm.fabs.f32(float [[X]]) -; CHECK-NEXT: [[RET:%.*]] = fcmp oeq float [[ABS]], 0x7FF0000000000000 +; CHECK-NEXT: [[RET:%.*]] = fcmp oeq float [[X]], 0x7FF0000000000000 ; CHECK-NEXT: ret i1 [[RET]] ; CHECK: if.else: ; CHECK-NEXT: ret i1 false @@ -80,10 +78,8 @@ define float @test4(float %x) { ; CHECK: if.then: ; CHECK-NEXT: ret float 1.000000e+00 ; CHECK: if.end: -; CHECK-NEXT: [[CMP_I:%.*]] = fcmp oeq float [[X]], 0.000000e+00 ; CHECK-NEXT: [[DIV:%.*]] = fdiv float 1.000000e+00, [[X]] -; CHECK-NEXT: [[RET:%.*]] = select i1 [[CMP_I]], float 1.000000e+00, float [[DIV]] -; CHECK-NEXT: ret float [[RET]] +; CHECK-NEXT: ret float [[DIV]] ; entry: %cmp = fcmp olt float %x, 0x3EB0C6F7A0000000 @@ -113,7 +109,7 @@ define i1 @test5(double %x, i1 %cond) { ; CHECK-NEXT: br label [[EXIT]] ; CHECK: exit: ; CHECK-NEXT: [[Y:%.*]] = phi double [ -1.000000e+00, [[ENTRY:%.*]] ], [ [[X]], [[IF_END]] ] -; CHECK-NEXT: [[RET:%.*]] = tail call i1 @llvm.is.fpclass.f64(double [[Y]], i32 411) +; CHECK-NEXT: [[RET:%.*]] = tail call i1 @llvm.is.fpclass.f64(double [[Y]], i32 408) ; CHECK-NEXT: ret i1 [[RET]] ; entry: @@ -138,8 +134,7 @@ define i1 @test6(double %x) { ; CHECK-NEXT: [[CMP:%.*]] = fcmp ogt double [[X]], 0.000000e+00 ; CHECK-NEXT: br i1 [[CMP]], label [[LAND_RHS:%.*]], label [[LAND_END:%.*]] ; CHECK: land.rhs: -; CHECK-NEXT: [[ABS:%.*]] = tail call double @llvm.fabs.f64(double [[X]]) -; CHECK-NEXT: [[AND_I:%.*]] = bitcast double [[ABS]] to i64 +; CHECK-NEXT: [[AND_I:%.*]] = bitcast double [[X]] to i64 ; CHECK-NEXT: [[CMP_I:%.*]] = icmp eq i64 [[AND_I]], 9218868437227405312 ; CHECK-NEXT: br label [[LAND_END]] ; CHECK: land.end: @@ -167,10 +162,10 @@ define i1 @test7(float %x) { ; CHECK-NEXT: [[COND:%.*]] = call i1 @llvm.is.fpclass.f32(float [[X]], i32 345) ; CHECK-NEXT: br i1 [[COND]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] ; CHECK: if.then: -; CHECK-NEXT: [[RET1:%.*]] = call i1 @llvm.is.fpclass.f32(float [[X]], i32 456) +; CHECK-NEXT: [[RET1:%.*]] = call i1 @llvm.is.fpclass.f32(float [[X]], i32 328) ; CHECK-NEXT: ret i1 [[RET1]] ; CHECK: if.else: -; CHECK-NEXT: [[RET2:%.*]] = call i1 @llvm.is.fpclass.f32(float [[X]], i32 456) +; CHECK-NEXT: [[RET2:%.*]] = call i1 @llvm.is.fpclass.f32(float [[X]], i32 128) ; CHECK-NEXT: ret i1 [[RET2]] ; %cond = call i1 @llvm.is.fpclass.f32(float %x, i32 345) From e1fa250ce726509bffb7c28907096904eb29dc49 Mon Sep 17 00:00:00 2001 From: Yingwei Zheng Date: Thu, 8 Feb 2024 22:44:45 +0800 Subject: [PATCH 3/5] fixup! [ValueTracking] Compute known FPClass from dominating condition --- llvm/lib/Analysis/ValueTracking.cpp | 15 ++++++--------- .../InstCombine/fpclass-from-dom-cond.ll | 3 +-- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index f84254f212d83..220ef32c2d3ce 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -4231,17 +4231,14 @@ static void computeKnownFPClassFromCond(const Value *V, Value *Cond, KnownFPClass &KnownFromContext) { CmpInst::Predicate Pred; Value *LHS; - Value *RHS; uint64_t ClassVal = 0; + const APFloat *CRHS; // TODO: handle sign-bit check idiom - if (match(Cond, m_FCmp(Pred, m_Value(LHS), m_Value(RHS)))) { - const APFloat *CRHS; - if (match(RHS, m_APFloat(CRHS))) { - auto [CmpVal, MaskIfTrue, MaskIfFalse] = fcmpImpliesClass( - Pred, *CxtI->getParent()->getParent(), LHS, *CRHS, LHS != V); - if (CmpVal == V) - KnownFromContext.knownNot(~(CondIsTrue ? MaskIfTrue : MaskIfFalse)); - } + if (match(Cond, m_FCmp(Pred, m_Value(LHS), m_APFloat(CRHS)))) { + auto [CmpVal, MaskIfTrue, MaskIfFalse] = fcmpImpliesClass( + Pred, *CxtI->getParent()->getParent(), LHS, *CRHS, LHS != V); + if (CmpVal == V) + KnownFromContext.knownNot(~(CondIsTrue ? MaskIfTrue : MaskIfFalse)); } else if (match(Cond, m_Intrinsic( m_Value(LHS), m_ConstantInt(ClassVal)))) { FPClassTest Mask = static_cast(ClassVal); diff --git a/llvm/test/Transforms/InstCombine/fpclass-from-dom-cond.ll b/llvm/test/Transforms/InstCombine/fpclass-from-dom-cond.ll index 48c6e91057094..471decf400119 100644 --- a/llvm/test/Transforms/InstCombine/fpclass-from-dom-cond.ll +++ b/llvm/test/Transforms/InstCombine/fpclass-from-dom-cond.ll @@ -134,8 +134,7 @@ define i1 @test6(double %x) { ; CHECK-NEXT: [[CMP:%.*]] = fcmp ogt double [[X]], 0.000000e+00 ; CHECK-NEXT: br i1 [[CMP]], label [[LAND_RHS:%.*]], label [[LAND_END:%.*]] ; CHECK: land.rhs: -; CHECK-NEXT: [[AND_I:%.*]] = bitcast double [[X]] to i64 -; CHECK-NEXT: [[CMP_I:%.*]] = icmp eq i64 [[AND_I]], 9218868437227405312 +; CHECK-NEXT: [[CMP_I:%.*]] = fcmp oeq double [[X]], 0x7FF0000000000000 ; CHECK-NEXT: br label [[LAND_END]] ; CHECK: land.end: ; CHECK-NEXT: [[RET:%.*]] = phi i1 [ false, [[ENTRY:%.*]] ], [ [[CMP_I]], [[LAND_RHS]] ] From 90629b949af156f423381d41d62f19566bcc8869 Mon Sep 17 00:00:00 2001 From: Yingwei Zheng Date: Fri, 9 Feb 2024 00:12:02 +0800 Subject: [PATCH 4/5] [ValueTracking] Add more tests. --- llvm/lib/Analysis/DomConditionCache.cpp | 2 + .../InstCombine/fpclass-from-dom-cond.ll | 64 +++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/llvm/lib/Analysis/DomConditionCache.cpp b/llvm/lib/Analysis/DomConditionCache.cpp index f1d2f4b5d8c0a..0c8c1ff518445 100644 --- a/llvm/lib/Analysis/DomConditionCache.cpp +++ b/llvm/lib/Analysis/DomConditionCache.cpp @@ -70,6 +70,8 @@ static void findAffectedValues(Value *Cond, } } // Handle patterns that computeKnownFPClass() support. + FCmpInst::Predicate Pred; + Value *A; if (match(Cond, m_FCmp(Pred, m_Value(A), m_Constant()))) AddAffected(A); if (match(Cond, m_Intrinsic(m_Value(A), m_Constant()))) diff --git a/llvm/test/Transforms/InstCombine/fpclass-from-dom-cond.ll b/llvm/test/Transforms/InstCombine/fpclass-from-dom-cond.ll index 471decf400119..e88415fe61a4f 100644 --- a/llvm/test/Transforms/InstCombine/fpclass-from-dom-cond.ll +++ b/llvm/test/Transforms/InstCombine/fpclass-from-dom-cond.ll @@ -177,6 +177,70 @@ if.else: ret i1 %ret2 } +; TODO: These two is.fpclass can be simplified. +define i1 @test8(float %x) { +; CHECK-LABEL: define i1 @test8( +; CHECK-SAME: float [[X:%.*]]) { +; CHECK-NEXT: [[ABS:%.*]] = call float @llvm.fabs.f32(float [[X]]) +; CHECK-NEXT: [[COND:%.*]] = fcmp oeq float [[ABS]], 0x7FF0000000000000 +; CHECK-NEXT: br i1 [[COND]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then: +; CHECK-NEXT: [[RET1:%.*]] = call i1 @llvm.is.fpclass.f32(float [[X]], i32 575) +; CHECK-NEXT: ret i1 [[RET1]] +; CHECK: if.else: +; CHECK-NEXT: [[RET2:%.*]] = call i1 @llvm.is.fpclass.f32(float [[X]], i32 575) +; CHECK-NEXT: ret i1 [[RET2]] +; + %abs = call float @llvm.fabs.f32(float %x) + %cond = fcmp oeq float %abs, 0x7FF0000000000000 + br i1 %cond, label %if.then, label %if.else +if.then: + %ret1 = call i1 @llvm.is.fpclass.f32(float %x, i32 575) + ret i1 %ret1 +if.else: + %ret2 = call i1 @llvm.is.fpclass.f32(float %x, i32 575) + ret i1 %ret2 +} + +define i1 @test9(float %x) { +; CHECK-LABEL: define i1 @test9( +; CHECK-SAME: float [[X:%.*]]) { +; CHECK-NEXT: [[COND:%.*]] = fcmp olt float [[X]], -1.000000e+00 +; CHECK-NEXT: br i1 [[COND]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then: +; CHECK-NEXT: ret i1 false +; CHECK: if.else: +; CHECK-NEXT: ret i1 false +; + %cond = fcmp olt float %x, -1.0 + br i1 %cond, label %if.then, label %if.else +if.then: + %ret1 = fcmp oeq float %x, 0x7FF0000000000000 + ret i1 %ret1 +if.else: + ret i1 false +} + +define i1 @test10(float %x) { +; CHECK-LABEL: define i1 @test10( +; CHECK-SAME: float [[X:%.*]]) { +; CHECK-NEXT: [[COND:%.*]] = fcmp olt float [[X]], -1.000000e+00 +; CHECK-NEXT: br i1 [[COND]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then: +; CHECK-NEXT: ret i1 false +; CHECK: if.else: +; CHECK-NEXT: ret i1 false +; + %cond = fcmp olt float %x, -1.0 + %neg = fneg float %x + br i1 %cond, label %if.then, label %if.else +if.then: + %ret1 = fcmp oeq float %neg, 0xFFF0000000000000 + ret i1 %ret1 +if.else: + ret i1 false +} + define i1 @test1_no_dominating(float %x, i1 %c) { ; CHECK-LABEL: define i1 @test1_no_dominating( ; CHECK-SAME: float [[X:%.*]], i1 [[C:%.*]]) { From 5738f8e4bd21a93feddc0c4b12191e212a1eca01 Mon Sep 17 00:00:00 2001 From: Yingwei Zheng Date: Sat, 10 Feb 2024 04:43:12 +0800 Subject: [PATCH 5/5] fixup! [ValueTracking] Compute known FPClass from dominating condition --- llvm/lib/Analysis/DomConditionCache.cpp | 14 +++-- .../InstCombine/fpclass-from-dom-cond.ll | 51 +++++++++++++++++++ 2 files changed, 57 insertions(+), 8 deletions(-) diff --git a/llvm/lib/Analysis/DomConditionCache.cpp b/llvm/lib/Analysis/DomConditionCache.cpp index 0c8c1ff518445..c07a8a76f111d 100644 --- a/llvm/lib/Analysis/DomConditionCache.cpp +++ b/llvm/lib/Analysis/DomConditionCache.cpp @@ -43,7 +43,7 @@ static void findAffectedValues(Value *Cond, if (!Visited.insert(V).second) continue; - ICmpInst::Predicate Pred; + CmpInst::Predicate Pred; Value *A, *B; // Only recurse into and/or if it matches the top-level and/or type. if (TopLevelIsAnd ? match(V, m_LogicalAnd(m_Value(A), m_Value(B))) @@ -67,15 +67,13 @@ static void findAffectedValues(Value *Cond, if (match(A, m_Add(m_Value(X), m_ConstantInt()))) AddAffected(X); } + } else if (match(Cond, m_CombineOr(m_FCmp(Pred, m_Value(A), m_Constant()), + m_Intrinsic( + m_Value(A), m_Constant())))) { + // Handle patterns that computeKnownFPClass() support. + AddAffected(A); } } - // Handle patterns that computeKnownFPClass() support. - FCmpInst::Predicate Pred; - Value *A; - if (match(Cond, m_FCmp(Pred, m_Value(A), m_Constant()))) - AddAffected(A); - if (match(Cond, m_Intrinsic(m_Value(A), m_Constant()))) - AddAffected(A); } void DomConditionCache::registerBranch(BranchInst *BI) { diff --git a/llvm/test/Transforms/InstCombine/fpclass-from-dom-cond.ll b/llvm/test/Transforms/InstCombine/fpclass-from-dom-cond.ll index e88415fe61a4f..5d4840159dc9a 100644 --- a/llvm/test/Transforms/InstCombine/fpclass-from-dom-cond.ll +++ b/llvm/test/Transforms/InstCombine/fpclass-from-dom-cond.ll @@ -241,6 +241,57 @@ if.else: ret i1 false } +; TODO: handle and/or conditions +define i1 @test11_and(float %x, i1 %cond2) { +; CHECK-LABEL: define i1 @test11_and( +; CHECK-SAME: float [[X:%.*]], i1 [[COND2:%.*]]) { +; CHECK-NEXT: [[COND:%.*]] = fcmp olt float [[X]], -1.000000e+00 +; CHECK-NEXT: [[AND:%.*]] = and i1 [[COND]], [[COND2]] +; CHECK-NEXT: br i1 [[AND]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then: +; CHECK-NEXT: [[RET1:%.*]] = fcmp oeq float [[X]], 0x7FF0000000000000 +; CHECK-NEXT: ret i1 [[RET1]] +; CHECK: if.else: +; CHECK-NEXT: ret i1 false +; + %cond = fcmp olt float %x, -1.0 + %neg = fneg float %x + %and = and i1 %cond, %cond2 + br i1 %and, label %if.then, label %if.else +if.then: + %ret1 = fcmp oeq float %neg, 0xFFF0000000000000 + ret i1 %ret1 +if.else: + ret i1 false +} + +; TODO: handle and/or conditions +define i1 @test12_or(float %x, i1 %cond2) { +; CHECK-LABEL: define i1 @test12_or( +; CHECK-SAME: float [[X:%.*]], i1 [[COND2:%.*]]) { +; CHECK-NEXT: entry: +; CHECK-NEXT: [[COND:%.*]] = fcmp ueq float [[X]], 0.000000e+00 +; CHECK-NEXT: [[OR:%.*]] = or i1 [[COND]], [[COND2]] +; CHECK-NEXT: br i1 [[OR]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then: +; CHECK-NEXT: ret i1 false +; CHECK: if.else: +; CHECK-NEXT: [[RET:%.*]] = call i1 @llvm.is.fpclass.f32(float [[X]], i32 783) +; CHECK-NEXT: ret i1 [[RET]] +; +entry: + %cond = fcmp ueq float %x, 0.000000e+00 + %or = or i1 %cond, %cond2 + br i1 %or, label %if.then, label %if.else + +if.then: + ret i1 false + +if.else: + %ret = call i1 @llvm.is.fpclass.f32(float %x, i32 783) + ret i1 %ret +} + define i1 @test1_no_dominating(float %x, i1 %c) { ; CHECK-LABEL: define i1 @test1_no_dominating( ; CHECK-SAME: float [[X:%.*]], i1 [[C:%.*]]) {