diff --git a/llvm/lib/Analysis/LazyValueInfo.cpp b/llvm/lib/Analysis/LazyValueInfo.cpp --- a/llvm/lib/Analysis/LazyValueInfo.cpp +++ b/llvm/lib/Analysis/LazyValueInfo.cpp @@ -26,6 +26,7 @@ #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Dominators.h" +#include "llvm/IR/InstrTypes.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Intrinsics.h" @@ -1147,6 +1148,57 @@ CR.getUnsignedMin().zext(BitWidth), APInt(BitWidth, 0))); } + // Recognize: + // icmp sgt (ashr X, ShAmtC), C --> icmp sgt X, ((C + 1) << ShAmtC) - 1 + // and friends. + // Preconditions: (C != SIGNED_MAX) && + // ((C+1) << ShAmtC != SIGNED_MIN) && + // (((C+1) << ShAmtC) >> ShAmtC) == (C+1) + const APInt *ShAmtC; + if (CmpInst::isSigned(EdgePred) && + match(LHS, m_AShr(m_Specific(Val), m_APInt(ShAmtC))) && + match(RHS, m_APInt(C))) { + APInt New = ((*C + 1) << *ShAmtC) - 1; + APInt MaxSigned = APInt::getSignedMaxValue(New.getBitWidth()); + APInt MinSigned = APInt::getSignedMinValue(New.getBitWidth()); + auto CheckPreConds = [&]() { + if (*C == MaxSigned) + return false; + APInt Shifted = (*C + 1) << *ShAmtC; + if (Shifted == MinSigned) + return false; + if ((Shifted.ashr(*ShAmtC)) != (*C + 1)) + return false; + return true; + }; + if (!CheckPreConds()) + return ValueLatticeElement::getOverdefined(); + APInt Lower, Upper; + switch (EdgePred) { + default: + llvm_unreachable("Unknown signed predicate!"); + case ICmpInst::ICMP_SGT: + Lower = New + 1; + Upper = MaxSigned; + break; + case ICmpInst::ICMP_SLE: + Lower = MinSigned; + Upper = New + 1; + break; + case ICmpInst::ICMP_SGE: + Lower = New; + Upper = MaxSigned; + break; + case ICmpInst::ICMP_SLT: + Lower = MinSigned; + Upper = New; + break; + } + + return ValueLatticeElement::getRange( + ConstantRange::getNonEmpty(Lower, Upper)); + } + return ValueLatticeElement::getOverdefined(); } diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/icmp.ll b/llvm/test/Transforms/CorrelatedValuePropagation/icmp.ll --- a/llvm/test/Transforms/CorrelatedValuePropagation/icmp.ll +++ b/llvm/test/Transforms/CorrelatedValuePropagation/icmp.ll @@ -1240,6 +1240,110 @@ ret <2 x i1> %cmp1 } +define void @ashr_sgt(i8 %x) { +; CHECK-LABEL: @ashr_sgt( +; CHECK-NEXT: [[S:%.*]] = ashr i8 [[X:%.*]], 2 +; CHECK-NEXT: [[C:%.*]] = icmp sgt i8 [[S]], 0 +; CHECK-NEXT: br i1 [[C]], label [[IF:%.*]], label [[ELSE:%.*]] +; CHECK: if: +; CHECK-NEXT: call void @check1(i1 true) +; CHECK-NEXT: [[C3:%.*]] = icmp ugt i8 [[X]], 4 +; CHECK-NEXT: call void @check1(i1 [[C3]]) +; CHECK-NEXT: ret void +; CHECK: else: +; CHECK-NEXT: ret void +; + %s = ashr i8 %x, 2 + %c = icmp sgt i8 %s, 0 + br i1 %c, label %if, label %else +if: + %c2 = icmp sgt i8 %x, 3 + call void @check1(i1 %c2) + %c3 = icmp sgt i8 %x, 4 + call void @check1(i1 %c3) + ret void +else: + ret void +} + +define void @ashr_sge(i8 %x) { +; CHECK-LABEL: @ashr_sge( +; CHECK-NEXT: [[S:%.*]] = ashr i8 [[X:%.*]], 2 +; CHECK-NEXT: [[C:%.*]] = icmp sge i8 [[S]], 0 +; CHECK-NEXT: br i1 [[C]], label [[IF:%.*]], label [[ELSE:%.*]] +; CHECK: if: +; CHECK-NEXT: call void @check1(i1 true) +; CHECK-NEXT: [[C3:%.*]] = icmp uge i8 [[X]], 4 +; CHECK-NEXT: call void @check1(i1 [[C3]]) +; CHECK-NEXT: ret void +; CHECK: else: +; CHECK-NEXT: ret void +; + %s = ashr i8 %x, 2 + %c = icmp sge i8 %s, 0 + br i1 %c, label %if, label %else +if: + %c2 = icmp sge i8 %x, 3 + call void @check1(i1 %c2) + %c3 = icmp sge i8 %x, 4 + call void @check1(i1 %c3) + ret void +else: + ret void +} + +define void @ashr_slt(i8 %x) { +; CHECK-LABEL: @ashr_slt( +; CHECK-NEXT: [[S:%.*]] = ashr i8 [[X:%.*]], 2 +; CHECK-NEXT: [[C:%.*]] = icmp slt i8 [[S]], 0 +; CHECK-NEXT: br i1 [[C]], label [[IF:%.*]], label [[ELSE:%.*]] +; CHECK: if: +; CHECK-NEXT: call void @check1(i1 true) +; CHECK-NEXT: [[C3:%.*]] = icmp slt i8 [[X]], 2 +; CHECK-NEXT: call void @check1(i1 [[C3]]) +; CHECK-NEXT: ret void +; CHECK: else: +; CHECK-NEXT: ret void +; + %s = ashr i8 %x, 2 + %c = icmp slt i8 %s, 0 + br i1 %c, label %if, label %else +if: + %c2 = icmp slt i8 %x, 3 + call void @check1(i1 %c2) + %c3 = icmp slt i8 %x, 2 + call void @check1(i1 %c3) + ret void +else: + ret void +} + +define void @ashr_sle(i8 %x) { +; CHECK-LABEL: @ashr_sle( +; CHECK-NEXT: [[S:%.*]] = ashr i8 [[X:%.*]], 2 +; CHECK-NEXT: [[C:%.*]] = icmp sle i8 [[S]], 0 +; CHECK-NEXT: br i1 [[C]], label [[IF:%.*]], label [[ELSE:%.*]] +; CHECK: if: +; CHECK-NEXT: call void @check1(i1 true) +; CHECK-NEXT: [[C3:%.*]] = icmp sle i8 [[X]], 2 +; CHECK-NEXT: call void @check1(i1 [[C3]]) +; CHECK-NEXT: ret void +; CHECK: else: +; CHECK-NEXT: ret void +; + %s = ashr i8 %x, 2 + %c = icmp sle i8 %s, 0 + br i1 %c, label %if, label %else +if: + %c2 = icmp sle i8 %x, 3 + call void @check1(i1 %c2) + %c3 = icmp sle i8 %x, 2 + call void @check1(i1 %c3) + ret void +else: + ret void +} + declare i8 @llvm.umin.i8(i8, i8) declare i8 @llvm.umax.i8(i8, i8) declare <2 x i8> @llvm.umin.v2i8(<2 x i8>, <2 x i8>)