diff options
-rw-r--r-- | llvm/lib/Transforms/Scalar/LoopUnswitch.cpp | 14 | ||||
-rw-r--r-- | llvm/test/Transforms/LoopUnswitch/basictest.ll | 39 |
2 files changed, 53 insertions, 0 deletions
diff --git a/llvm/lib/Transforms/Scalar/LoopUnswitch.cpp b/llvm/lib/Transforms/Scalar/LoopUnswitch.cpp index 60910bab090..6d99caf1dff 100644 --- a/llvm/lib/Transforms/Scalar/LoopUnswitch.cpp +++ b/llvm/lib/Transforms/Scalar/LoopUnswitch.cpp @@ -500,6 +500,20 @@ bool LoopUnswitch::processCurrentLoop() { return true; } + // Do not unswitch loops containing convergent operations, as we might be + // making them control dependent on the unswitch value when they were not + // before. + // FIXME: This could be refined to only bail if the convergent operation is + // not already control-dependent on the unswitch value. + for (const auto BB : currentLoop->blocks()) { + for (const auto &I : *BB) { + const auto CI = dyn_cast<CallInst>(&I); + if (!CI) continue; + if (CI->isConvergent()) + return false; + } + } + // Do not do non-trivial unswitch while optimizing for size. // FIXME: Use Function::optForSize(). if (OptimizeForSize || diff --git a/llvm/test/Transforms/LoopUnswitch/basictest.ll b/llvm/test/Transforms/LoopUnswitch/basictest.ll index e990144d5cc..a02a463764d 100644 --- a/llvm/test/Transforms/LoopUnswitch/basictest.ll +++ b/llvm/test/Transforms/LoopUnswitch/basictest.ll @@ -64,5 +64,44 @@ loop_exit: ; CHECK: } } +; This simple test would normally unswitch, but should be inhibited by the presence of +; the convergent call that is not control-dependent on the unswitch condition. + +; CHECK-LABEL: @test3( +define i32 @test3(i32* %var) { + %mem = alloca i32 + store i32 2, i32* %mem + %c = load i32, i32* %mem + + br label %loop_begin + +loop_begin: + + %var_val = load i32, i32* %var + +; CHECK: call void @conv() +; CHECK-NOT: call void @conv() + call void @conv() convergent + + switch i32 %c, label %default [ + i32 1, label %inc + i32 2, label %dec + ] + +inc: + call void @incf() noreturn nounwind + br label %loop_begin +dec: + call void @decf() noreturn nounwind + br label %loop_begin +default: + br label %loop_exit +loop_exit: + ret i32 0 +; CHECK: } +} + + declare void @incf() noreturn declare void @decf() noreturn +declare void @conv() convergent |