From 2f10e78ad197bfe97c8fbe35758bd0a925dc8e03 Mon Sep 17 00:00:00 2001 From: Owen Anderson Date: Fri, 9 Oct 2015 18:40:20 +0000 Subject: [PATCH] Teach LoopUnswitch not to perform non-trivial unswitching on loops containing convergent operations. Doing so could cause the post-unswitching convergent ops to be control-dependent on the unswitch condition where they were not before. This check could be refined to allow unswitching where the convergent operation was already control-dependent on the unswitch condition. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@249874 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Transforms/Scalar/LoopUnswitch.cpp | 14 ++++++++ test/Transforms/LoopUnswitch/basictest.ll | 39 +++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/lib/Transforms/Scalar/LoopUnswitch.cpp b/lib/Transforms/Scalar/LoopUnswitch.cpp index 60910bab090..6d99caf1dff 100644 --- a/lib/Transforms/Scalar/LoopUnswitch.cpp +++ b/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(&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/test/Transforms/LoopUnswitch/basictest.ll b/test/Transforms/LoopUnswitch/basictest.ll index e990144d5cc..a02a463764d 100644 --- a/test/Transforms/LoopUnswitch/basictest.ll +++ b/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 -- 2.34.1