diff --git a/llvm/lib/Analysis/DomConditionCache.cpp b/llvm/lib/Analysis/DomConditionCache.cpp index c07a8a76f111d..274f3ff44b2a6 100644 --- a/llvm/lib/Analysis/DomConditionCache.cpp +++ b/llvm/lib/Analysis/DomConditionCache.cpp @@ -66,6 +66,11 @@ static void findAffectedValues(Value *Cond, // A > C3 && A < C4. if (match(A, m_Add(m_Value(X), m_ConstantInt()))) AddAffected(X); + // Handle icmp slt/sgt (bitcast X to int), 0/-1, which is supported by + // computeKnownFPClass(). + if ((Pred == ICmpInst::ICMP_SLT || Pred == ICmpInst::ICMP_SGT) && + match(A, m_ElementWiseBitCast(m_Value(X)))) + Affected.push_back(X); } } else if (match(Cond, m_CombineOr(m_FCmp(Pred, m_Value(A), m_Constant()), m_Intrinsic( diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index 6c42facea3b2b..cc1d5b74dcfc5 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -4272,7 +4272,7 @@ static void computeKnownFPClassFromCond(const Value *V, Value *Cond, Value *LHS; uint64_t ClassVal = 0; const APFloat *CRHS; - // TODO: handle sign-bit check idiom + const APInt *RHS; 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); @@ -4282,6 +4282,15 @@ static void computeKnownFPClassFromCond(const Value *V, Value *Cond, m_Value(LHS), m_ConstantInt(ClassVal)))) { FPClassTest Mask = static_cast(ClassVal); KnownFromContext.knownNot(CondIsTrue ? ~Mask : Mask); + } else if (match(Cond, m_ICmp(Pred, m_ElementWiseBitCast(m_Value(LHS)), + m_APInt(RHS)))) { + bool TrueIfSigned; + if (!isSignBitCheck(Pred, *RHS, TrueIfSigned)) + return; + if (TrueIfSigned == CondIsTrue) + KnownFromContext.signBitMustBeOne(); + else + KnownFromContext.signBitMustBeZero(); } } diff --git a/llvm/test/Transforms/InstCombine/fpclass-from-dom-cond.ll b/llvm/test/Transforms/InstCombine/fpclass-from-dom-cond.ll index 5d4840159dc9a..d40cd7fd503ec 100644 --- a/llvm/test/Transforms/InstCombine/fpclass-from-dom-cond.ll +++ b/llvm/test/Transforms/InstCombine/fpclass-from-dom-cond.ll @@ -320,3 +320,118 @@ if.else: %ret = call i1 @llvm.is.fpclass.f32(float %x, i32 783) ret i1 %ret } + +define float @test_signbit_check(float %x, i1 %cond) { +; CHECK-LABEL: define float @test_signbit_check( +; CHECK-SAME: float [[X:%.*]], i1 [[COND:%.*]]) { +; CHECK-NEXT: [[I32:%.*]] = bitcast float [[X]] to i32 +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I32]], 0 +; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN1:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then1: +; CHECK-NEXT: [[FNEG:%.*]] = fneg float [[X]] +; CHECK-NEXT: br label [[IF_END:%.*]] +; CHECK: if.else: +; CHECK-NEXT: br i1 [[COND]], label [[IF_THEN2:%.*]], label [[IF_END]] +; CHECK: if.then2: +; CHECK-NEXT: br label [[IF_END]] +; CHECK: if.end: +; CHECK-NEXT: [[VALUE:%.*]] = phi float [ [[FNEG]], [[IF_THEN1]] ], [ [[X]], [[IF_THEN2]] ], [ [[X]], [[IF_ELSE]] ] +; CHECK-NEXT: ret float [[VALUE]] +; + %i32 = bitcast float %x to i32 + %cmp = icmp slt i32 %i32, 0 + br i1 %cmp, label %if.then1, label %if.else + +if.then1: + %fneg = fneg float %x + br label %if.end + +if.else: + br i1 %cond, label %if.then2, label %if.end + +if.then2: + br label %if.end + +if.end: + %value = phi float [ %fneg, %if.then1 ], [ %x, %if.then2 ], [ %x, %if.else ] + %ret = call float @llvm.fabs.f32(float %value) + ret float %ret +} + +define float @test_signbit_check_fail(float %x, i1 %cond) { +; CHECK-LABEL: define float @test_signbit_check_fail( +; CHECK-SAME: float [[X:%.*]], i1 [[COND:%.*]]) { +; CHECK-NEXT: [[I32:%.*]] = bitcast float [[X]] to i32 +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I32]], 0 +; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN1:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then1: +; CHECK-NEXT: [[FNEG:%.*]] = fneg float [[X]] +; CHECK-NEXT: br label [[IF_END:%.*]] +; CHECK: if.else: +; CHECK-NEXT: br i1 [[COND]], label [[IF_THEN2:%.*]], label [[IF_END]] +; CHECK: if.then2: +; CHECK-NEXT: [[FNEG2:%.*]] = fneg float [[X]] +; CHECK-NEXT: br label [[IF_END]] +; CHECK: if.end: +; CHECK-NEXT: [[VALUE:%.*]] = phi float [ [[FNEG]], [[IF_THEN1]] ], [ [[FNEG2]], [[IF_THEN2]] ], [ [[X]], [[IF_ELSE]] ] +; CHECK-NEXT: [[RET:%.*]] = call float @llvm.fabs.f32(float [[VALUE]]) +; CHECK-NEXT: ret float [[RET]] +; + %i32 = bitcast float %x to i32 + %cmp = icmp slt i32 %i32, 0 + br i1 %cmp, label %if.then1, label %if.else + +if.then1: + %fneg = fneg float %x + br label %if.end + +if.else: + br i1 %cond, label %if.then2, label %if.end + +if.then2: + %fneg2 = fneg float %x + br label %if.end + +if.end: + %value = phi float [ %fneg, %if.then1 ], [ %fneg2, %if.then2 ], [ %x, %if.else ] + %ret = call float @llvm.fabs.f32(float %value) + ret float %ret +} + +define <2 x float> @test_signbit_check_wrong_type(<2 x float> %x, i1 %cond) { +; CHECK-LABEL: define <2 x float> @test_signbit_check_wrong_type( +; CHECK-SAME: <2 x float> [[X:%.*]], i1 [[COND:%.*]]) { +; CHECK-NEXT: [[I32:%.*]] = bitcast <2 x float> [[X]] to i64 +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[I32]], 0 +; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN1:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then1: +; CHECK-NEXT: [[FNEG:%.*]] = fneg <2 x float> [[X]] +; CHECK-NEXT: br label [[IF_END:%.*]] +; CHECK: if.else: +; CHECK-NEXT: br i1 [[COND]], label [[IF_THEN2:%.*]], label [[IF_END]] +; CHECK: if.then2: +; CHECK-NEXT: br label [[IF_END]] +; CHECK: if.end: +; CHECK-NEXT: [[VALUE:%.*]] = phi <2 x float> [ [[FNEG]], [[IF_THEN1]] ], [ [[X]], [[IF_THEN2]] ], [ [[X]], [[IF_ELSE]] ] +; CHECK-NEXT: [[RET:%.*]] = call <2 x float> @llvm.fabs.v2f32(<2 x float> [[VALUE]]) +; CHECK-NEXT: ret <2 x float> [[RET]] +; + %i32 = bitcast <2 x float> %x to i64 + %cmp = icmp slt i64 %i32, 0 + br i1 %cmp, label %if.then1, label %if.else + +if.then1: + %fneg = fneg <2 x float> %x + br label %if.end + +if.else: + br i1 %cond, label %if.then2, label %if.end + +if.then2: + br label %if.end + +if.end: + %value = phi <2 x float> [ %fneg, %if.then1 ], [ %x, %if.then2 ], [ %x, %if.else ] + %ret = call <2 x float> @llvm.fabs.v2f32(<2 x float> %value) + ret <2 x float> %ret +}