diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -5999,10 +5999,16 @@ auto *CI = dyn_cast(Inst); if (!CI) return false; - const Function *Callee = CI->getCalledFunction(); + + // The called function depends on the set of threads executing it, which + // could change if the call is moved to a different location in control + // flow. + if (CI->isConvergent()) + return false; // The called function could have undefined behavior or side-effects, even // if marked readnone nounwind. + const Function *Callee = CI->getCalledFunction(); return Callee && Callee->isSpeculatable(); } case Instruction::VAArg: diff --git a/llvm/test/Transforms/SimplifyCFG/attr-convergent.ll b/llvm/test/Transforms/SimplifyCFG/attr-convergent.ll --- a/llvm/test/Transforms/SimplifyCFG/attr-convergent.ll +++ b/llvm/test/Transforms/SimplifyCFG/attr-convergent.ll @@ -3,6 +3,7 @@ ; Checks that the SimplifyCFG pass won't duplicate a call to a function marked ; convergent. ; +; CHECK-LABEL: @check ; CHECK: call void @barrier ; CHECK-NOT: call void @barrier define void @check(i1 %cond, ptr %out) { @@ -25,4 +26,23 @@ ret void } +; CHECK-LABEL: @dont_speculate_convergent +; CHECK: entry: +; CHECK: then: +; CHECK: call i32 @speculatable_convergent +; CHECK: end: +define i32 @dont_speculate_convergent(i1 %cond1, i32 %in) { +entry: + br i1 %cond1, label %then, label %end + +then: + %v = call i32 @speculatable_convergent(i32 %in) + br label %end + +end: + %r = phi i32 [ 0, %entry ], [ %v, %then ] + ret i32 %r +} + declare void @barrier() convergent +declare i32 @speculatable_convergent(i32) convergent readnone speculatable