diff --git a/llvm/lib/Transforms/Utils/LoopSimplify.cpp b/llvm/lib/Transforms/Utils/LoopSimplify.cpp --- a/llvm/lib/Transforms/Utils/LoopSimplify.cpp +++ b/llvm/lib/Transforms/Utils/LoopSimplify.cpp @@ -230,6 +230,27 @@ if (!Preheader) return nullptr; + // Treat the presence of convergent functions conservatively. The + // transformation is invalid if calls to certain convergent + // functions (like an AMDGPU barrier) get included in the resulting + // inner loop. But blocks meant for the inner loop will be + // identified later at a point where it's too late to abort the + // transformation. Also, the convergent attribute is not really + // sufficient to express the semantics of functions that are + // affected by this transformation. So we choose to back off if such + // a function call is present until a better alternative becomes + // available. This is similar to the conservative treatment of + // convergent function calls in GVNHoist and JumpThreading. + for (auto BB : L->blocks()) { + for (auto &II : *BB) { + if (auto CI = dyn_cast(&II)) { + if (CI->isConvergent()) { + return nullptr; + } + } + } + } + // The header is not a landing pad; preheader insertion should ensure this. BasicBlock *Header = L->getHeader(); assert(!Header->isEHPad() && "Can't insert backedge to EH pad"); diff --git a/llvm/test/Transforms/LoopSimplify/convergent.ll b/llvm/test/Transforms/LoopSimplify/convergent.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/LoopSimplify/convergent.ll @@ -0,0 +1,25 @@ +; RUN: opt < %s -S -loop-simplify | FileCheck %s + +; Don't separate out nested loops if a convergent call is present + +; CHECK-NOT: BB1.outer +; CHECK: BB1.backedge + +define i32 @test(i1 %loop_cond, i1 %exit_cond, i32 %init) { +entry: + br label %BB1 + +BB1: + %indvar = phi i32 [%indvar, %BB1], [%inc, %BB2], [%init, %entry] + call void @f() convergent + br i1 %loop_cond, label %BB1, label %BB2 + +BB2: + %inc = add i32 %indvar, 1 + br i1 %exit_cond, label %exit, label %BB1 + +exit: + ret i32 %inc +} + +declare void @f() convergent