[instcombine] Collapse trivial and recurrences

If we have a recurrence of the form <Start, And, Step> we know that the value taken by the recurrence stabilizes on the first iteration (provided step is loop invariant). We can exploit that fact to remove the loop carried dependence in the recurrence.

Differential Revision: https://reviews.llvm.org/D97578 (and part)
This commit is contained in:
Philip Reames
2021-03-08 09:13:51 -08:00
parent 7a64cc4a76
commit 239a618180
4 changed files with 30 additions and 18 deletions

View File

@@ -764,6 +764,16 @@ constexpr unsigned MaxAnalysisRecursionDepth = 6;
bool matchSimpleRecurrence(const PHINode *P, BinaryOperator *&BO,
Value *&Start, Value *&Step);
/// Analogous to the above, but starting from the binary operator
inline bool matchSimpleRecurrence(const BinaryOperator *I, PHINode *&P,
Value *&Start, Value *&Step) {
BinaryOperator *BO = nullptr;
P = dyn_cast<PHINode>(I->getOperand(0));
if (!P)
P = dyn_cast<PHINode>(I->getOperand(1));
return P && matchSimpleRecurrence(P, BO, Start, Step) && BO == I;
}
/// Return true if RHS is known to be implied true by LHS. Return false if
/// RHS is known to be implied false by LHS. Otherwise, return None if no
/// implication can be made.

View File

@@ -1987,6 +1987,12 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) {
if (sinkNotIntoOtherHandOfAndOrOr(I))
return &I;
// An and recurrence w/loop invariant step is equivelent to (and start, step)
PHINode *PN = nullptr;
Value *Start = nullptr, *Step = nullptr;
if (matchSimpleRecurrence(&I, PN, Start, Step) && DT.dominates(Step, PN))
return replaceInstUsesWith(I, Builder.CreateAnd(Start, Step));
return nullptr;
}

View File

@@ -23,17 +23,16 @@ define dso_local i32 @main() {
; CHECK-NEXT: [[I6:%.*]] = load i32, i32* @a, align 4
; CHECK-NEXT: [[I24:%.*]] = load i32, i32* @b, align 4
; CHECK-NEXT: [[D_PROMOTED9:%.*]] = load i32, i32* @d, align 4
; CHECK-NEXT: br label [[BB13_PREHEADER:%.*]]
; CHECK: bb13.preheader:
; CHECK-NEXT: [[I8_LCSSA10:%.*]] = phi i32 [ [[D_PROMOTED9]], [[BB:%.*]] ], [ [[I8:%.*]], [[BB19_PREHEADER:%.*]] ]
; CHECK-NEXT: [[I8]] = and i32 [[I8_LCSSA10]], [[I6]]
; CHECK-NEXT: [[I21:%.*]] = icmp eq i32 [[I8]], 0
; CHECK-NEXT: br i1 [[I21]], label [[BB13_PREHEADER_BB27_THREAD_SPLIT_CRIT_EDGE:%.*]], label [[BB19_PREHEADER]]
; CHECK-NEXT: [[TMP0:%.*]] = and i32 [[D_PROMOTED9]], [[I6]]
; CHECK-NEXT: [[I21:%.*]] = icmp eq i32 [[TMP0]], 0
; CHECK-NEXT: br label [[BB1:%.*]]
; CHECK: bb1:
; CHECK-NEXT: br i1 [[I21]], label [[BB13_PREHEADER_BB27_THREAD_SPLIT_CRIT_EDGE:%.*]], label [[BB19_PREHEADER:%.*]]
; CHECK: bb19.preheader:
; CHECK-NEXT: [[I26:%.*]] = urem i32 [[I24]], [[I8]]
; CHECK-NEXT: [[I26:%.*]] = urem i32 [[I24]], [[TMP0]]
; CHECK-NEXT: store i32 [[I26]], i32* @e, align 4
; CHECK-NEXT: [[I30_NOT:%.*]] = icmp eq i32 [[I26]], 0
; CHECK-NEXT: br i1 [[I30_NOT]], label [[BB32_LOOPEXIT:%.*]], label [[BB13_PREHEADER]]
; CHECK-NEXT: br i1 [[I30_NOT]], label [[BB32_LOOPEXIT:%.*]], label [[BB1]]
; CHECK: bb13.preheader.bb27.thread.split_crit_edge:
; CHECK-NEXT: store i32 -1, i32* @f, align 4
; CHECK-NEXT: store i32 0, i32* @d, align 4
@@ -41,7 +40,7 @@ define dso_local i32 @main() {
; CHECK-NEXT: br label [[BB32:%.*]]
; CHECK: bb32.loopexit:
; CHECK-NEXT: store i32 -1, i32* @f, align 4
; CHECK-NEXT: store i32 [[I8]], i32* @d, align 4
; CHECK-NEXT: store i32 [[TMP0]], i32* @d, align 4
; CHECK-NEXT: br label [[BB32]]
; CHECK: bb32:
; CHECK-NEXT: [[C_SINK:%.*]] = phi i32* [ @c, [[BB32_LOOPEXIT]] ], [ @e, [[BB13_PREHEADER_BB27_THREAD_SPLIT_CRIT_EDGE]] ]

View File

@@ -89,9 +89,8 @@ define i64 @test_and(i64 %a) {
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[A:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
; CHECK-NEXT: [[IV_NEXT]] = and i64 [[IV]], 15
; CHECK-NEXT: tail call void @use(i64 [[IV_NEXT]])
; CHECK-NEXT: [[TMP0:%.*]] = and i64 [[A:%.*]], 15
; CHECK-NEXT: tail call void @use(i64 [[TMP0]])
; CHECK-NEXT: br label [[LOOP]]
;
entry:
@@ -110,9 +109,8 @@ define i64 @test_and2(i64 %a, i64 %b) {
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[A:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
; CHECK-NEXT: [[IV_NEXT]] = and i64 [[IV]], [[B:%.*]]
; CHECK-NEXT: tail call void @use(i64 [[IV_NEXT]])
; CHECK-NEXT: [[TMP0:%.*]] = and i64 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: tail call void @use(i64 [[TMP0]])
; CHECK-NEXT: br label [[LOOP]]
;
entry:
@@ -130,9 +128,8 @@ define i64 @test_and3(i64 %a, i64 %b) {
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[A:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
; CHECK-NEXT: [[IV_NEXT]] = and i64 [[IV]], [[B:%.*]]
; CHECK-NEXT: tail call void @use(i64 [[IV_NEXT]])
; CHECK-NEXT: [[TMP0:%.*]] = and i64 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: tail call void @use(i64 [[TMP0]])
; CHECK-NEXT: br label [[LOOP]]
;
entry: