diff --git a/llvm/lib/Transforms/Scalar/LoopUnswitch.cpp b/llvm/lib/Transforms/Scalar/LoopUnswitch.cpp --- a/llvm/lib/Transforms/Scalar/LoopUnswitch.cpp +++ b/llvm/lib/Transforms/Scalar/LoopUnswitch.cpp @@ -661,7 +661,7 @@ // FIXME: Use Function::hasOptSize(). if (OptimizeForSize || LoopHeader->getParent()->hasFnAttribute(Attribute::OptimizeForSize)) - return false; + return Changed; // Run through the instructions in the loop, keeping track of three things: // @@ -685,10 +685,10 @@ if (!CB) continue; if (CB->isConvergent()) - return false; + return Changed; if (auto *II = dyn_cast(&I)) if (!II->getUnwindDest()->canSplitPredecessors()) - return false; + return Changed; if (auto *II = dyn_cast(&I)) if (II->getIntrinsicID() == Intrinsic::experimental_guard) Guards.push_back(II); diff --git a/llvm/test/Transforms/LoopUnswitch/convergent-hoist-modified.ll b/llvm/test/Transforms/LoopUnswitch/convergent-hoist-modified.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/LoopUnswitch/convergent-hoist-modified.ll @@ -0,0 +1,42 @@ +; RUN: opt -loop-unswitch -enable-new-pm=0 %s -S | FileCheck %s + +; When hoisting simple values out from a loop, and not being able to unswitch +; the loop due to the convergent call, the pass would return an incorrect +; Modified status. This was caught by the pass return status check that is +; hidden under EXPENSIVE_CHECKS. + +; CHECK-LABEL: entry: +; CHECK-NEXT: %0 = call i32 @llvm.objectsize.i32.p0i8(i8* bitcast (%struct.anon* @b to i8*), i1 false, i1 false, i1 false) +; CHECK-NEXT: %1 = icmp uge i32 %0, 1 +; CHECK-NEXT: br label %for.cond + +%struct.anon = type { i16 } + +@b = global %struct.anon zeroinitializer, align 1 + +; Function Attrs: nounwind +define i16 @c() #0 { +entry: + br label %for.cond + +for.cond: ; preds = %cont, %entry + br label %for.inc + +for.inc: ; preds = %for.cond + %0 = call i32 @llvm.objectsize.i32.p0i8(i8* bitcast (%struct.anon* @b to i8*), i1 false, i1 false, i1 false) + %1 = icmp uge i32 %0, 1 + br i1 %1, label %cont, label %cont + +cont: ; preds = %for.inc + call void @conv() convergent + %2 = load i16, i16* getelementptr inbounds (%struct.anon, %struct.anon* @b, i32 0, i32 0), align 1 + br label %for.cond +} + +; Function Attrs: nounwind readnone speculatable willreturn +declare i32 @llvm.objectsize.i32.p0i8(i8*, i1 immarg, i1 immarg, i1 immarg) #1 + +declare void @conv() convergent + +attributes #0 = { nounwind } +attributes #1 = { nounwind readnone speculatable willreturn } diff --git a/llvm/test/Transforms/LoopUnswitch/invoke-hoist-modified.ll b/llvm/test/Transforms/LoopUnswitch/invoke-hoist-modified.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/LoopUnswitch/invoke-hoist-modified.ll @@ -0,0 +1,53 @@ +; RUN: opt -loop-unswitch -enable-new-pm=0 %s -S | FileCheck %s + +; When hoisting simple values out from a loop, and not being able to unswitch +; the loop due to the invoke instruction, the pass would return an incorrect +; Modified status. This was caught by the pass return status check that is +; hidden under EXPENSIVE_CHECKS. + +; CHECK-LABEL: for.cond: +; CHECK-NEXT: %0 = call i32 @llvm.objectsize.i32.p0i8(i8* bitcast (%struct.anon* @b to i8*), i1 false, i1 false, i1 false) +; CHECK-NEXT: %1 = icmp uge i32 %0, 1 +; CHECK-NEXT: br label %for.inc + +%struct.anon = type { i16 } + +@b = global %struct.anon zeroinitializer, align 1 + +; Function Attrs: nounwind +define i32 @c() #0 personality i32 (...)* @__CxxFrameHandler3 { +entry: + br label %for.cond + +for.cond: ; preds = %cont, %entry + br label %for.inc + +for.inc: ; preds = %for.cond + %0 = call i32 @llvm.objectsize.i32.p0i8(i8* bitcast (%struct.anon* @b to i8*), i1 false, i1 false, i1 false) + %1 = icmp uge i32 %0, 1 + br i1 %1, label %delete.notnull, label %delete.notnull + +delete.notnull: ; preds = %for.inc + invoke void @g() to label %invoke.cont unwind label %lpad + +invoke.cont: ; preds = %delete.notnull + br label %for.inc + +lpad: ; preds = %delete.notnull + %cp = cleanuppad within none [] + cleanupret from %cp unwind to caller + +cont: ; preds = %for.inc + %2 = load i16, i16* getelementptr inbounds (%struct.anon, %struct.anon* @b, i32 0, i32 0), align 1 + br label %for.cond +} + +; Function Attrs: nounwind readnone speculatable willreturn +declare i32 @llvm.objectsize.i32.p0i8(i8*, i1 immarg, i1 immarg, i1 immarg) #1 + +declare void @g() + +declare i32 @__CxxFrameHandler3(...) + +attributes #0 = { nounwind } +attributes #1 = { nounwind readnone speculatable willreturn } diff --git a/llvm/test/Transforms/LoopUnswitch/optsize-hoist-modified.ll b/llvm/test/Transforms/LoopUnswitch/optsize-hoist-modified.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/LoopUnswitch/optsize-hoist-modified.ll @@ -0,0 +1,39 @@ +; RUN: opt -loop-unswitch -enable-new-pm=0 %s -S | FileCheck %s + +; When hoisting simple values out from a loop, and not being able to attempt to +; non-trivally unswitch the loop, due to the optsize attribute, the pass would +; return an incorrect Modified status. This was caught by the pass return +; status check that is hidden under EXPENSIVE_CHECKS. + +; CHECK-LABEL: entry: +; CHECK-NEXT: %0 = call i32 @llvm.objectsize.i32.p0i8(i8* bitcast (%struct.anon* @b to i8*), i1 false, i1 false, i1 false) +; CHECK-NEXT: %1 = icmp uge i32 %0, 1 +; CHECK-NEXT: br label %for.cond + +%struct.anon = type { i16 } + +@b = global %struct.anon zeroinitializer, align 1 + +; Function Attrs: minsize nounwind optsize +define i16 @c() #0 { +entry: + br label %for.cond + +for.cond: ; preds = %cont, %entry + br label %for.inc + +for.inc: ; preds = %for.cond + %0 = call i32 @llvm.objectsize.i32.p0i8(i8* bitcast (%struct.anon* @b to i8*), i1 false, i1 false, i1 false) + %1 = icmp uge i32 %0, 1 + br i1 %1, label %cont, label %cont + +cont: ; preds = %for.inc + %2 = load i16, i16* getelementptr inbounds (%struct.anon, %struct.anon* @b, i32 0, i32 0), align 1 + br label %for.cond +} + +; Function Attrs: nounwind readnone speculatable willreturn +declare i32 @llvm.objectsize.i32.p0i8(i8*, i1 immarg, i1 immarg, i1 immarg) #1 + +attributes #0 = { minsize nounwind optsize } +attributes #1 = { nounwind readnone speculatable willreturn }