diff --git a/llvm/lib/Transforms/Scalar/LoopInterchange.cpp b/llvm/lib/Transforms/Scalar/LoopInterchange.cpp --- a/llvm/lib/Transforms/Scalar/LoopInterchange.cpp +++ b/llvm/lib/Transforms/Scalar/LoopInterchange.cpp @@ -323,9 +323,10 @@ /// LoopInterchangeLegality checks if it is legal to interchange the loop. class LoopInterchangeLegality { public: - LoopInterchangeLegality(Loop *Outer, Loop *Inner, ScalarEvolution *SE, + LoopInterchangeLegality(Loop *Outer, Loop *Inner, LoopInfo *LI, + DominatorTree *DT, ScalarEvolution *SE, OptimizationRemarkEmitter *ORE) - : OuterLoop(Outer), InnerLoop(Inner), SE(SE), ORE(ORE) {} + : OuterLoop(Outer), InnerLoop(Inner), LI(LI), DT(DT), SE(SE), ORE(ORE) {} /// Check if the loops can be interchanged. bool canInterchangeLoops(unsigned InnerLoopId, unsigned OuterLoopId, @@ -356,6 +357,8 @@ Loop *OuterLoop; Loop *InnerLoop; + LoopInfo *LI; + DominatorTree *DT; ScalarEvolution *SE; /// Interface to emit optimization remarks. @@ -539,7 +542,7 @@ std::vector> &DependencyMatrix) { LLVM_DEBUG(dbgs() << "Processing InnerLoopId = " << InnerLoopId << " and OuterLoopId = " << OuterLoopId << "\n"); - LoopInterchangeLegality LIL(OuterLoop, InnerLoop, SE, ORE); + LoopInterchangeLegality LIL(OuterLoop, InnerLoop, LI, DT, SE, ORE); if (!LIL.canInterchangeLoops(InnerLoopId, OuterLoopId, DependencyMatrix)) { LLVM_DEBUG(dbgs() << "Not interchanging loops. Cannot prove legality.\n"); return false; @@ -1014,6 +1017,26 @@ return false; } + // Check if either outer and inner loop contains instructions guarded by + // control flow that have side effects. + for (BasicBlock *BB : OuterLoop->blocks()) { + Loop *L = LI->getLoopFor(BB); + if (DT->dominates(BB, L->getLoopLatch())) + continue; + if (containsUnsafeInstructions(BB)) { + LLVM_DEBUG(dbgs() << "Instructions guarded by control flow may break " + "loop interchange.\n"); + ORE->emit([&]() { + return OptimizationRemarkMissed( + DEBUG_TYPE, "InvalidInstructionWithControlFlow", + OuterLoop->getStartLoc(), OuterLoop->getHeader()) + << "Instructions guarded by control flow may break loop " + "interchange.\n"; + }); + return false; + } + } + return true; } diff --git a/llvm/test/Transforms/LoopInterchange/pr47523.ll b/llvm/test/Transforms/LoopInterchange/pr47523.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/LoopInterchange/pr47523.ll @@ -0,0 +1,59 @@ +; RUN: opt -loop-interchange -debug-only=loop-interchange 2>&1 %s | FileCheck %s + +; Test case of PR47523. + +; CHECK: Instructions guarded by control flow may break loop interchange. +; CHECK-NEXT: Not interchanging loops. Cannot prove legality. + +%struct.a = type { i8 } + +@c = common dso_local global [1 x %struct.a] zeroinitializer, align 1 +@f = dso_local local_unnamed_addr global [4 x [9 x i32]] [[9 x i32] [i32 5, i32 3, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0], [9 x i32] zeroinitializer, [9 x i32] zeroinitializer, [9 x i32] zeroinitializer], align 4 +@g = common dso_local local_unnamed_addr global i32 0, align 4 + +define dso_local i32 @main() local_unnamed_addr { +for.cond2.preheader.preheader.i: + %0 = sext i32 undef to i64 + br label %for.cond2.preheader.i + +for.cond2.preheader.i: ; preds = %for.end11.i, %for.cond2.preheader.preheader.i + %indvars.iv20.i = phi i64 [ %0, %for.cond2.preheader.preheader.i ], [ %indvars.iv.next21.i, %for.end11.i ] + br label %for.body4.i + +for.body4.i: ; preds = %if.end.i, %for.cond2.preheader.i + %indvars.iv.i = phi i64 [ 0, %for.cond2.preheader.i ], [ %indvars.iv.next.i, %if.end.i ] + %arrayidx6.i = getelementptr inbounds [4 x [9 x i32]], [4 x [9 x i32]]* @f, i64 0, i64 %indvars.iv.i, i64 %indvars.iv20.i + %1 = load i32, i32* %arrayidx6.i, align 4 + %tobool.i = icmp eq i32 %1, 0 + br i1 %tobool.i, label %land.end.i, label %land.rhs.i + +land.rhs.i: ; preds = %for.body4.i + store i16 3, i16* bitcast (i32* @g to i16*), align 4 + br label %land.end.i + +land.end.i: ; preds = %land.rhs.i, %for.body4.i + br i1 icmp eq (i64 urem (i64 zext (i16 ptrtoint ([1 x %struct.a]* @c to i16) to i64), i64 4073709551606), i64 0), label %if.end.i, label %if.then.i + +if.then.i: ; preds = %land.end.i + %2 = load i16, i16* bitcast (i32* @g to i16*), align 4 + %inc.i = add i16 %2, 1 + store i16 %inc.i, i16* bitcast (i32* @g to i16*), align 4 + br label %if.end.i + +if.end.i: ; preds = %if.then.i, %land.end.i + %indvars.iv.next.i = add nuw nsw i64 %indvars.iv.i, 1 + %exitcond.i = icmp eq i64 %indvars.iv.next.i, 3 + br i1 %exitcond.i, label %for.end11.i, label %for.body4.i + +for.end11.i: ; preds = %if.end.i + %indvars.iv.next21.i = add nsw i64 %indvars.iv20.i, 1 + %cmp.i = icmp slt i64 %indvars.iv20.i, 2 + br i1 %cmp.i, label %for.cond2.preheader.i, label %for.cond.for.end14_crit_edge.i + +for.cond.for.end14_crit_edge.i: ; preds = %for.end11.i + br label %h.exit + +h.exit: ; preds = %for.cond.for.end14_crit_edge.i + %3 = load i32, i32* @g, align 4 + ret i32 0 +} diff --git a/llvm/test/Transforms/LoopInterchange/pr48057.ll b/llvm/test/Transforms/LoopInterchange/pr48057.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/LoopInterchange/pr48057.ll @@ -0,0 +1,72 @@ +; RUN: opt -loop-interchange -debug-only=loop-interchange 2>&1 %s | FileCheck %s + +; Test case of PR48057. + +; CHECK: Instructions guarded by control flow may break loop interchange. +; CHECK-NEXT: Not interchanging loops. Cannot prove legality. + +@b = dso_local global [7 x [8 x i8]] [[8 x i8] zeroinitializer, [8 x i8] zeroinitializer, [8 x i8] zeroinitializer, [8 x i8] zeroinitializer, [8 x i8] c"\05\00\00\00\00\00\00\00", [8 x i8] zeroinitializer, [8 x i8] c"\02\03\00\00\00\00\00\00"], align 16 +@c = dso_local global i32 0, align 4 +@d = dso_local global i32 0, align 4 +@e = dso_local global i16 0, align 2 + +define dso_local i32 @main() { +entry: + call fastcc void @f() + %0 = load i16, i16* @e, align 2 + %conv = sext i16 %0 to i32 + ret i32 %conv +} + +define internal fastcc void @f() { +entry: + %.pr = load i32, i32* @c, align 4 + %cmp2 = icmp slt i32 %.pr, 8 + br i1 %cmp2, label %for.cond1.preheader.preheader, label %for.end13 + +for.cond1.preheader.preheader: ; preds = %entry + %0 = sext i32 %.pr to i64 + %1 = sub i32 7, %.pr + %2 = zext i32 %1 to i64 + %3 = add i64 %0, %2 + br label %for.cond1.preheader + +for.cond1.preheader: ; preds = %for.cond1.preheader.preheader, %for.inc12 + %indvars.iv4 = phi i64 [ %0, %for.cond1.preheader.preheader ], [ %indvars.iv.next5, %for.inc12 ] + br label %for.body2 + +for.body2: ; preds = %for.cond1.preheader, %land.end + %indvars.iv = phi i64 [ 4, %for.cond1.preheader ], [ %indvars.iv.next, %land.end ] + %4 = add nuw nsw i64 %indvars.iv, 2 + %arrayidx4 = getelementptr inbounds [7 x [8 x i8]], [7 x [8 x i8]]* @b, i64 0, i64 %4, i64 %indvars.iv4 + %5 = load i8, i8* %arrayidx4, align 1 + %tobool5.not = icmp eq i8 %5, 0 + br i1 %tobool5.not, label %land.end, label %land.rhs + +land.rhs: ; preds = %for.body2 + %arrayidx8 = getelementptr inbounds [7 x [8 x i8]], [7 x [8 x i8]]* @b, i64 0, i64 %indvars.iv, i64 0 + %6 = load i8, i8* %arrayidx8, align 8 + %conv9 = sext i8 %6 to i16 + store i16 %conv9, i16* @e, align 2 + br label %land.end + +land.end: ; preds = %land.rhs, %for.body2 + %indvars.iv.next = add nsw i64 %indvars.iv, -1 + %tobool.not = icmp eq i64 %indvars.iv.next, 0 + br i1 %tobool.not, label %for.inc12, label %for.body2 + +for.inc12: ; preds = %land.end + %indvars.iv.next5 = add nsw i64 %indvars.iv4, 1 + %exitcond = icmp ne i64 %indvars.iv.next5, 8 + br i1 %exitcond, label %for.cond1.preheader, label %for.cond.for.end13_crit_edge + +for.cond.for.end13_crit_edge: ; preds = %for.inc12 + %7 = add i64 %3, 1 + %8 = trunc i64 %7 to i32 + store i32 0, i32* @d, align 4 + store i32 %8, i32* @c, align 4 + br label %for.end13 + +for.end13: ; preds = %for.cond.for.end13_crit_edge, %entry + ret void +}