Skip to content

Commit

Permalink
[LVI][CVP] Use block value when simplifying icmps
Browse files Browse the repository at this point in the history
Add a flag to getPredicateAt() that allows making use of the block
value. This allows us to take into account range information from
the current block, rather than only information that is threaded
over edges, making the icmp simplification in CVP a lot more
powerful.

I'm not changing getPredicateAt() to use the block value
unconditionally to avoid any impact on the JumpThreading pass,
which is somewhat picky about LVI query order.

Most test changes here are just icmps that now get dropped (while
previously only a result used in a return was replaced). The three
tests in icmp.ll show some representative improvements. Some of
the folds this enables have been covered by IPSCCP in the meantime,
but LVI can reason about some cases which are hard to support in
IPSCCP, such as in test_br_cmp_with_offset.

The compile-time time cost of doing this is fairly minimal, with
a ~0.05% CTMark regression for ReleaseThinLTO:
https://llvm-compile-time-tracker.com/compare.php?from=709d03f8af4da4204849a70f01798e7cebba2e32&to=6236fd503761f43c99f4537121e057a01056f185&stat=instructions

This is because the block values will typically already be queried
and cached by other CVP optimizations anyway.

Differential Revision: https://reviews.llvm.org/D69686
  • Loading branch information
nikic committed Sep 27, 2020
1 parent 50bd71e commit fe79061
Show file tree
Hide file tree
Showing 6 changed files with 14 additions and 49 deletions.
7 changes: 4 additions & 3 deletions llvm/include/llvm/Analysis/LazyValueInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,11 @@ class LazyValueInfo {
Instruction *CxtI = nullptr);

/// Determine whether the specified value comparison with a constant is known
/// to be true or false at the specified instruction
/// (from an assume intrinsic). Pred is a CmpInst predicate.
/// to be true or false at the specified instruction.
/// \p Pred is a CmpInst predicate. If \p UseBlockValue is true, the block
/// value is also taken into account.
Tristate getPredicateAt(unsigned Pred, Value *V, Constant *C,
Instruction *CxtI);
Instruction *CxtI, bool UseBlockValue = false);

/// Determine whether the specified value is known to be a constant at the
/// specified instruction. Return null if not.
Expand Down
7 changes: 5 additions & 2 deletions llvm/lib/Analysis/LazyValueInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1744,7 +1744,7 @@ LazyValueInfo::getPredicateOnEdge(unsigned Pred, Value *V, Constant *C,

LazyValueInfo::Tristate
LazyValueInfo::getPredicateAt(unsigned Pred, Value *V, Constant *C,
Instruction *CxtI) {
Instruction *CxtI, bool UseBlockValue) {
// Is or is not NonNull are common predicates being queried. If
// isKnownNonZero can tell us the result of the predicate, we can
// return it quickly. But this is only a fastpath, and falling
Expand All @@ -1758,7 +1758,10 @@ LazyValueInfo::getPredicateAt(unsigned Pred, Value *V, Constant *C,
else if (Pred == ICmpInst::ICMP_NE)
return LazyValueInfo::True;
}
ValueLatticeElement Result = getImpl(PImpl, AC, M).getValueAt(V, CxtI);

ValueLatticeElement Result = UseBlockValue
? getImpl(PImpl, AC, M).getValueInBlock(V, CxtI->getParent(), CxtI)
: getImpl(PImpl, AC, M).getValueAt(V, CxtI);
Tristate Ret = getPredicateResult(Pred, C, Result, DL, TLI);
if (Ret != Unknown)
return Ret;
Expand Down
13 changes: 2 additions & 11 deletions llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -304,18 +304,9 @@ static bool processCmp(CmpInst *Cmp, LazyValueInfo *LVI) {
if (!C)
return false;

// As a policy choice, we choose not to waste compile time on anything where
// the comparison is testing local values. While LVI can sometimes reason
// about such cases, it's not its primary purpose. We do make sure to do
// the block local query for uses from terminator instructions, but that's
// handled in the code for each terminator. As an exception, we allow phi
// nodes, for which LVI can thread the condition into predecessors.
auto *I = dyn_cast<Instruction>(Op0);
if (I && I->getParent() == Cmp->getParent() && !isa<PHINode>(I))
return false;

LazyValueInfo::Tristate Result =
LVI->getPredicateAt(Cmp->getPredicate(), Op0, C, Cmp);
LVI->getPredicateAt(Cmp->getPredicate(), Op0, C, Cmp,
/*UseBlockValue=*/true);
if (Result == LazyValueInfo::Unknown)
return false;

Expand Down
23 changes: 0 additions & 23 deletions llvm/test/Transforms/CorrelatedValuePropagation/basic.ll
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,6 @@ declare nonnull i8* @return_nonnull()
define i1 @call_attribute() {
; CHECK-LABEL: @call_attribute(
; CHECK-NEXT: [[A:%.*]] = call i8* @return_nonnull()
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8* [[A]], null
; CHECK-NEXT: br label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: ret i1 false
Expand All @@ -319,7 +318,6 @@ define i1 @umin(i32 %a, i32 %b) {
; CHECK: b_guard:
; CHECK-NEXT: [[SEL_CMP:%.*]] = icmp ult i32 [[A]], [[B]]
; CHECK-NEXT: [[MIN:%.*]] = select i1 [[SEL_CMP]], i32 [[A]], i32 [[B]]
; CHECK-NEXT: [[RES:%.*]] = icmp eq i32 [[MIN]], 7
; CHECK-NEXT: br label [[NEXT:%.*]]
; CHECK: next:
; CHECK-NEXT: ret i1 false
Expand Down Expand Up @@ -356,7 +354,6 @@ define i1 @smin(i32 %a, i32 %b) {
; CHECK: b_guard:
; CHECK-NEXT: [[SEL_CMP:%.*]] = icmp sle i32 [[A]], [[B]]
; CHECK-NEXT: [[MIN:%.*]] = select i1 [[SEL_CMP]], i32 [[A]], i32 [[B]]
; CHECK-NEXT: [[RES:%.*]] = icmp eq i32 [[MIN]], 7
; CHECK-NEXT: br label [[NEXT:%.*]]
; CHECK: next:
; CHECK-NEXT: ret i1 false
Expand Down Expand Up @@ -393,7 +390,6 @@ define i1 @smax(i32 %a, i32 %b) {
; CHECK: b_guard:
; CHECK-NEXT: [[SEL_CMP:%.*]] = icmp sge i32 [[A]], [[B]]
; CHECK-NEXT: [[MAX:%.*]] = select i1 [[SEL_CMP]], i32 [[A]], i32 [[B]]
; CHECK-NEXT: [[RES:%.*]] = icmp eq i32 [[MAX]], 7
; CHECK-NEXT: br label [[NEXT:%.*]]
; CHECK: next:
; CHECK-NEXT: ret i1 false
Expand Down Expand Up @@ -430,7 +426,6 @@ define i1 @umax(i32 %a, i32 %b) {
; CHECK: b_guard:
; CHECK-NEXT: [[SEL_CMP:%.*]] = icmp uge i32 [[A]], [[B]]
; CHECK-NEXT: [[MAX:%.*]] = select i1 [[SEL_CMP]], i32 [[A]], i32 [[B]]
; CHECK-NEXT: [[RES:%.*]] = icmp eq i32 [[MAX]], 7
; CHECK-NEXT: br label [[NEXT:%.*]]
; CHECK: next:
; CHECK-NEXT: ret i1 false
Expand Down Expand Up @@ -465,7 +460,6 @@ define i1 @clamp_low1(i32 %a) {
; CHECK-NEXT: [[SEL_CMP:%.*]] = icmp eq i32 [[A]], 5
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], -1
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[SEL_CMP]], i32 5, i32 [[A]]
; CHECK-NEXT: [[RES:%.*]] = icmp eq i32 [[SEL]], 4
; CHECK-NEXT: br label [[NEXT:%.*]]
; CHECK: next:
; CHECK-NEXT: ret i1 false
Expand Down Expand Up @@ -497,7 +491,6 @@ define i1 @clamp_low2(i32 %a) {
; CHECK-NEXT: [[SEL_CMP:%.*]] = icmp ne i32 [[A]], 5
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], -1
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[SEL_CMP]], i32 [[A]], i32 5
; CHECK-NEXT: [[RES:%.*]] = icmp eq i32 [[SEL]], 4
; CHECK-NEXT: br label [[NEXT:%.*]]
; CHECK: next:
; CHECK-NEXT: ret i1 false
Expand Down Expand Up @@ -529,7 +522,6 @@ define i1 @clamp_high1(i32 %a) {
; CHECK-NEXT: [[SEL_CMP:%.*]] = icmp eq i32 [[A]], 5
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], 1
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[SEL_CMP]], i32 5, i32 [[A]]
; CHECK-NEXT: [[RES:%.*]] = icmp eq i32 [[SEL]], 6
; CHECK-NEXT: br label [[NEXT:%.*]]
; CHECK: next:
; CHECK-NEXT: ret i1 false
Expand Down Expand Up @@ -561,7 +553,6 @@ define i1 @clamp_high2(i32 %a) {
; CHECK-NEXT: [[SEL_CMP:%.*]] = icmp ne i32 [[A]], 5
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], 1
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[SEL_CMP]], i32 [[A]], i32 5
; CHECK-NEXT: [[RES:%.*]] = icmp eq i32 [[SEL]], 6
; CHECK-NEXT: br label [[NEXT:%.*]]
; CHECK: next:
; CHECK-NEXT: ret i1 false
Expand Down Expand Up @@ -594,7 +585,6 @@ define i1 @clamp_high3(i32 %a) {
; CHECK-NEXT: [[SEL_CMP:%.*]] = icmp ne i32 [[A]], 5
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], 100
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[SEL_CMP]], i32 [[A]], i32 5
; CHECK-NEXT: [[RES:%.*]] = icmp eq i32 [[SEL]], 105
; CHECK-NEXT: br label [[NEXT:%.*]]
; CHECK: next:
; CHECK-NEXT: ret i1 false
Expand Down Expand Up @@ -821,7 +811,6 @@ define i1 @zext_unknown(i8 %a) {
; CHECK-LABEL: @zext_unknown(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A32:%.*]] = zext i8 [[A:%.*]] to i32
; CHECK-NEXT: [[CMP:%.*]] = icmp sle i32 [[A32]], 256
; CHECK-NEXT: br label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: ret i1 true
Expand All @@ -839,7 +828,6 @@ define i1 @trunc_unknown(i32 %a) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A8:%.*]] = trunc i32 [[A:%.*]] to i8
; CHECK-NEXT: [[A32:%.*]] = sext i8 [[A8]] to i32
; CHECK-NEXT: [[CMP:%.*]] = icmp sle i32 [[A32]], 128
; CHECK-NEXT: br label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: ret i1 true
Expand Down Expand Up @@ -894,7 +882,6 @@ define i1 @and_unknown(i32 %a) {
; CHECK-LABEL: @and_unknown(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[AND:%.*]] = and i32 [[A:%.*]], 128
; CHECK-NEXT: [[CMP:%.*]] = icmp sle i32 [[AND]], 128
; CHECK-NEXT: br label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: ret i1 true
Expand All @@ -911,7 +898,6 @@ define i1 @lshr_unknown(i32 %a) {
; CHECK-LABEL: @lshr_unknown(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[AND:%.*]] = lshr i32 [[A:%.*]], 30
; CHECK-NEXT: [[CMP:%.*]] = icmp sle i32 [[AND]], 128
; CHECK-NEXT: br label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: ret i1 true
Expand All @@ -928,7 +914,6 @@ define i1 @urem_unknown(i32 %a) {
; CHECK-LABEL: @urem_unknown(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[UREM:%.*]] = urem i32 [[A:%.*]], 30
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[UREM]], 30
; CHECK-NEXT: br label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: ret i1 true
Expand All @@ -945,8 +930,6 @@ define i1 @srem_unknown(i32 %a) {
; CHECK-LABEL: @srem_unknown(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[SREM:%.*]] = srem i32 [[A:%.*]], 30
; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[SREM]], 30
; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i32 [[SREM]], -30
; CHECK-NEXT: br i1 undef, label [[EXIT1:%.*]], label [[EXIT2:%.*]]
; CHECK: exit1:
; CHECK-NEXT: ret i1 true
Expand All @@ -968,8 +951,6 @@ define i1 @sdiv_unknown(i32 %a) {
; CHECK-LABEL: @sdiv_unknown(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[SREM:%.*]] = sdiv i32 [[A:%.*]], 123
; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[SREM]], 17459217
; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i32 [[SREM]], -17459217
; CHECK-NEXT: br i1 undef, label [[EXIT1:%.*]], label [[EXIT2:%.*]]
; CHECK: exit1:
; CHECK-NEXT: ret i1 true
Expand All @@ -991,7 +972,6 @@ define i1 @uadd_sat_unknown(i32 %a) {
; CHECK-LABEL: @uadd_sat_unknown(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[VAL:%.*]] = call i32 @llvm.uadd.sat.i32(i32 [[A:%.*]], i32 100)
; CHECK-NEXT: [[CMP1:%.*]] = icmp uge i32 [[VAL]], 100
; CHECK-NEXT: [[CMP2:%.*]] = icmp ugt i32 [[VAL]], 100
; CHECK-NEXT: br i1 undef, label [[EXIT1:%.*]], label [[EXIT2:%.*]]
; CHECK: exit1:
Expand All @@ -1014,7 +994,6 @@ define i1 @usub_sat_unknown(i32 %a) {
; CHECK-LABEL: @usub_sat_unknown(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[VAL:%.*]] = call i32 @llvm.usub.sat.i32(i32 [[A:%.*]], i32 100)
; CHECK-NEXT: [[CMP1:%.*]] = icmp ule i32 [[VAL]], -101
; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i32 [[VAL]], -101
; CHECK-NEXT: br i1 undef, label [[EXIT1:%.*]], label [[EXIT2:%.*]]
; CHECK: exit1:
Expand All @@ -1037,7 +1016,6 @@ define i1 @sadd_sat_unknown(i32 %a) {
; CHECK-LABEL: @sadd_sat_unknown(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[VAL:%.*]] = call i32 @llvm.sadd.sat.i32(i32 [[A:%.*]], i32 100)
; CHECK-NEXT: [[CMP1:%.*]] = icmp sge i32 [[VAL]], -2147483548
; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i32 [[VAL]], -2147483548
; CHECK-NEXT: br i1 undef, label [[EXIT1:%.*]], label [[EXIT2:%.*]]
; CHECK: exit1:
Expand All @@ -1060,7 +1038,6 @@ define i1 @ssub_sat_unknown(i32 %a) {
; CHECK-LABEL: @ssub_sat_unknown(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[VAL:%.*]] = call i32 @llvm.ssub.sat.i32(i32 [[A:%.*]], i32 100)
; CHECK-NEXT: [[CMP1:%.*]] = icmp sle i32 [[VAL]], 2147483547
; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[VAL]], 2147483547
; CHECK-NEXT: br i1 undef, label [[EXIT1:%.*]], label [[EXIT2:%.*]]
; CHECK: exit1:
Expand Down
9 changes: 3 additions & 6 deletions llvm/test/Transforms/CorrelatedValuePropagation/icmp.ll
Original file line number Diff line number Diff line change
Expand Up @@ -381,8 +381,7 @@ define i1 @test12(i32 %x) {
; CHECK-NEXT: [[MUL:%.*]] = mul nuw nsw i64 [[ZEXT]], 7
; CHECK-NEXT: [[SHR:%.*]] = lshr i64 [[MUL]], 32
; CHECK-NEXT: [[TRUNC:%.*]] = trunc i64 [[SHR]] to i32
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[TRUNC]], 7
; CHECK-NEXT: ret i1 [[CMP]]
; CHECK-NEXT: ret i1 true
;
%zext = zext i32 %x to i64
%mul = mul nuw i64 %zext, 7
Expand All @@ -396,9 +395,8 @@ define i1 @test13(i8 %x, i64* %p) {
; CHECK-LABEL: @test13(
; CHECK-NEXT: [[ZEXT:%.*]] = zext i8 [[X:%.*]] to i64
; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i64 [[ZEXT]], 128
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[ADD]], 384
; CHECK-NEXT: store i64 [[ADD]], i64* [[P:%.*]], align 8
; CHECK-NEXT: ret i1 [[CMP]]
; CHECK-NEXT: ret i1 true
;
%zext = zext i8 %x to i64
%add = add nuw nsw i64 %zext, 128
Expand Down Expand Up @@ -627,8 +625,7 @@ define i1 @test_br_cmp_with_offset(i64 %idx) {
; CHECK-NEXT: br i1 [[CMP1]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
; CHECK: if.true:
; CHECK-NEXT: [[IDX_OFF2:%.*]] = add nsw i64 [[IDX]], -1
; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i64 [[IDX_OFF2]], 10
; CHECK-NEXT: ret i1 [[CMP2]]
; CHECK-NEXT: ret i1 true
; CHECK: if.false:
; CHECK-NEXT: ret i1 undef
;
Expand Down
4 changes: 0 additions & 4 deletions llvm/test/Transforms/CorrelatedValuePropagation/range.ll
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,6 @@ sw.default:
define i1 @test8(i64* %p) {
; CHECK-LABEL: @test8(
; CHECK-NEXT: [[A:%.*]] = load i64, i64* [[P:%.*]], align 4, [[RNG0:!range !.*]]
; CHECK-NEXT: [[RES:%.*]] = icmp eq i64 [[A]], 0
; CHECK-NEXT: ret i1 false
;
%a = load i64, i64* %p, !range !{i64 4, i64 255}
Expand All @@ -252,7 +251,6 @@ define i1 @test8(i64* %p) {
define i1 @test9(i64* %p) {
; CHECK-LABEL: @test9(
; CHECK-NEXT: [[A:%.*]] = load i64, i64* [[P:%.*]], align 4, [[RNG1:!range !.*]]
; CHECK-NEXT: [[RES:%.*]] = icmp eq i64 [[A]], 0
; CHECK-NEXT: ret i1 true
;
%a = load i64, i64* %p, !range !{i64 0, i64 1}
Expand All @@ -263,7 +261,6 @@ define i1 @test9(i64* %p) {
define i1 @test10(i64* %p) {
; CHECK-LABEL: @test10(
; CHECK-NEXT: [[A:%.*]] = load i64, i64* [[P:%.*]], align 4, [[RNG2:!range !.*]]
; CHECK-NEXT: [[RES:%.*]] = icmp eq i64 [[A]], 0
; CHECK-NEXT: ret i1 false
;
%a = load i64, i64* %p, !range !{i64 4, i64 8, i64 15, i64 20}
Expand All @@ -277,7 +274,6 @@ define i1 @test11() {
; CHECK-LABEL: @test11(
; CHECK-NEXT: [[POSITIVE:%.*]] = load i32, i32* @g, align 4, [[RNG3:!range !.*]]
; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[POSITIVE]], 1
; CHECK-NEXT: [[TEST:%.*]] = icmp sgt i32 [[ADD]], 0
; CHECK-NEXT: br label [[NEXT:%.*]]
; CHECK: next:
; CHECK-NEXT: ret i1 true
Expand Down

0 comments on commit fe79061

Please sign in to comment.