Skip to content

Commit

Permalink
[LoopInterchange] Remove a limitation in LoopInterchange legality
Browse files Browse the repository at this point in the history
There was a limitation in legality that in the original inner loop latch,
no instruction was allowed between the induction variable increment
and the branch instruction. This is because we used to split the
inner latch at the induction variable increment instruction. Since
now we have split at the inner latch branch instruction and have
properly duplicated instructions over to the split block, we remove
this limitation.

Please refer to the test case updates to see how we now interchange
loops where instructions exist between the induction variable
increment and the branch instruction.

Reviewed By: bmahjour

Differential Revision: https://reviews.llvm.org/D115238
  • Loading branch information
CongzheUalberta committed Jan 6, 2022
1 parent 9b1d27b commit c251bfc
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 87 deletions.
73 changes: 0 additions & 73 deletions llvm/lib/Transforms/Scalar/LoopInterchange.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -793,7 +793,6 @@ bool LoopInterchangeLegality::findInductionAndReductions(
// This function indicates the current limitations in the transform as a result
// of which we do not proceed.
bool LoopInterchangeLegality::currentLimitations() {
BasicBlock *InnerLoopPreHeader = InnerLoop->getLoopPreheader();
BasicBlock *InnerLoopLatch = InnerLoop->getLoopLatch();

// transform currently expects the loop latches to also be the exiting
Expand Down Expand Up @@ -888,78 +887,6 @@ bool LoopInterchangeLegality::currentLimitations() {
return true;
}

// TODO: Current limitation: Since we split the inner loop latch at the point
// were induction variable is incremented (induction.next); We cannot have
// more than 1 user of induction.next since it would result in broken code
// after split.
// e.g.
// for(i=0;i<N;i++) {
// for(j = 0;j<M;j++) {
// A[j+1][i+2] = A[j][i]+k;
// }
// }
Instruction *InnerIndexVarInc = nullptr;
if (InnerInductionVar->getIncomingBlock(0) == InnerLoopPreHeader)
InnerIndexVarInc =
dyn_cast<Instruction>(InnerInductionVar->getIncomingValue(1));
else
InnerIndexVarInc =
dyn_cast<Instruction>(InnerInductionVar->getIncomingValue(0));

if (!InnerIndexVarInc) {
LLVM_DEBUG(
dbgs() << "Did not find an instruction to increment the induction "
<< "variable.\n");
ORE->emit([&]() {
return OptimizationRemarkMissed(DEBUG_TYPE, "NoIncrementInInner",
InnerLoop->getStartLoc(),
InnerLoop->getHeader())
<< "The inner loop does not increment the induction variable.";
});
return true;
}

// Since we split the inner loop latch on this induction variable. Make sure
// we do not have any instruction between the induction variable and branch
// instruction.

bool FoundInduction = false;
for (const Instruction &I :
llvm::reverse(InnerLoopLatch->instructionsWithoutDebug())) {
if (isa<BranchInst>(I) || isa<CmpInst>(I) || isa<TruncInst>(I) ||
isa<ZExtInst>(I))
continue;

// We found an instruction. If this is not induction variable then it is not
// safe to split this loop latch.
if (!I.isIdenticalTo(InnerIndexVarInc)) {
LLVM_DEBUG(dbgs() << "Found unsupported instructions between induction "
<< "variable increment and branch.\n");
ORE->emit([&]() {
return OptimizationRemarkMissed(
DEBUG_TYPE, "UnsupportedInsBetweenInduction",
InnerLoop->getStartLoc(), InnerLoop->getHeader())
<< "Found unsupported instruction between induction variable "
"increment and branch.";
});
return true;
}

FoundInduction = true;
break;
}
// The loop latch ended and we didn't find the induction variable return as
// current limitation.
if (!FoundInduction) {
LLVM_DEBUG(dbgs() << "Did not find the induction variable.\n");
ORE->emit([&]() {
return OptimizationRemarkMissed(DEBUG_TYPE, "NoIndutionVariable",
InnerLoop->getStartLoc(),
InnerLoop->getHeader())
<< "Did not find the induction variable.";
});
return true;
}
return false;
}

Expand Down
9 changes: 3 additions & 6 deletions llvm/test/Transforms/LoopInterchange/currentLimitation.ll
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,16 @@ target triple = "x86_64-unknown-linux-gnu"
@C = common global [100 x [100 x i64]] zeroinitializer

;;--------------------------------------Test case 01------------------------------------
;; [FIXME] This loop though valid is currently not interchanged due to the limitation that we cannot split the inner loop latch due to multiple use of inner induction
;; variable.(used to increment the loop counter and to access A[j+1][i+1]
;; This loop can be interchanged with -da-disable-delinearization-checks, otherwise it cannot
;; be interchanged due to dependence.
;; for(int i=0;i<N-1;i++)
;; for(int j=1;j<N-1;j++)
;; A[j+1][i+1] = A[j+1][i+1] + k;

; IR-LABEL: @interchange_01
; IR-NOT: split

; CHECK: Name: Dependence
; CHECK-NEXT: Function: interchange_01

; DELIN: Name: UnsupportedInsBetweenInduction
; DELIN: Name: Interchanged
; DELIN-NEXT: Function: interchange_01
define void @interchange_01(i32 %k, i32 %N) {
entry:
Expand Down
20 changes: 15 additions & 5 deletions llvm/test/Transforms/LoopInterchange/interchangeable.ll
Original file line number Diff line number Diff line change
Expand Up @@ -146,23 +146,33 @@ for.end11:
define void @interchange_10() {
; CHECK-LABEL: @interchange_10(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[FOR2_PREHEADER:%.*]]
; CHECK: for1.header.preheader:
; CHECK-NEXT: br label [[FOR1_HEADER:%.*]]
; CHECK: for1.header:
; CHECK-NEXT: [[J23:%.*]] = phi i64 [ 1, [[ENTRY:%.*]] ], [ [[J_NEXT24:%.*]], [[FOR1_INC10:%.*]] ]
; CHECK-NEXT: [[J23:%.*]] = phi i64 [ [[J_NEXT24:%.*]], [[FOR1_INC10:%.*]] ], [ 1, [[FOR1_HEADER_PREHEADER:%.*]] ]
; CHECK-NEXT: [[J_NEXT24]] = add nuw nsw i64 [[J23]], 1
; CHECK-NEXT: br label [[FOR2_SPLIT1:%.*]]
; CHECK: for2.preheader:
; CHECK-NEXT: br label [[FOR2:%.*]]
; CHECK: for2:
; CHECK-NEXT: [[J:%.*]] = phi i64 [ [[J_NEXT:%.*]], [[FOR2]] ], [ 1, [[FOR1_HEADER]] ]
; CHECK-NEXT: [[J_NEXT]] = add nuw nsw i64 [[J]], 1
; CHECK-NEXT: [[J:%.*]] = phi i64 [ [[TMP0:%.*]], [[FOR2_SPLIT:%.*]] ], [ 1, [[FOR2_PREHEADER]] ]
; CHECK-NEXT: br label [[FOR1_HEADER_PREHEADER]]
; CHECK: for2.split1:
; CHECK-NEXT: [[J_NEXT:%.*]] = add nuw nsw i64 [[J]], 1
; CHECK-NEXT: [[ARRAYIDX5:%.*]] = getelementptr inbounds [100 x [100 x i64]], [100 x [100 x i64]]* @A, i64 0, i64 [[J]], i64 [[J23]]
; CHECK-NEXT: store i64 [[J]], i64* [[ARRAYIDX5]]
; CHECK-NEXT: [[ARRAYIDX10:%.*]] = getelementptr inbounds [100 x [100 x i64]], [100 x [100 x i64]]* @A, i64 0, i64 [[J]], i64 [[J_NEXT24]]
; CHECK-NEXT: store i64 [[J23]], i64* [[ARRAYIDX10]]
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[J]], 99
; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR1_INC10]], label [[FOR2]]
; CHECK-NEXT: br label [[FOR1_INC10]]
; CHECK: for2.split:
; CHECK-NEXT: [[TMP0]] = add nuw nsw i64 [[J]], 1
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[J]], 99
; CHECK-NEXT: br i1 [[TMP1]], label [[FOR_END12:%.*]], label [[FOR2]]
; CHECK: for1.inc10:
; CHECK-NEXT: [[EXITCOND26:%.*]] = icmp eq i64 [[J23]], 98
; CHECK-NEXT: br i1 [[EXITCOND26]], label [[FOR_END12:%.*]], label [[FOR1_HEADER]]
; CHECK-NEXT: br i1 [[EXITCOND26]], label [[FOR2_SPLIT]], label [[FOR1_HEADER]]
; CHECK: for.end12:
; CHECK-NEXT: ret void
;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,12 +130,12 @@ define void @test02(i32 %k, i32 %N) {
; CHECK-NEXT: - String: Cannot interchange loops due to dependences.
; CHECK-NEXT: ...

; DELIN: --- !Missed
; DELIN: --- !Passed
; DELIN-NEXT: Pass: loop-interchange
; DELIN-NEXT: Name: UnsupportedInsBetweenInduction
; DELIN-NEXT: Name: Interchanged
; DELIN-NEXT: Function: test02
; DELIN-NEXT: Args:
; DELIN-NEXT: - String: Found unsupported instruction between induction variable increment and branch.
; DELIN-NEXT: - String: Loop interchanged with enclosing loop.
; DELIN-NEXT: ...

;;-----------------------------------Test case 03-------------------------------
Expand Down

0 comments on commit c251bfc

Please sign in to comment.