Index: lib/Transforms/Scalar/JumpThreading.cpp =================================================================== --- lib/Transforms/Scalar/JumpThreading.cpp +++ lib/Transforms/Scalar/JumpThreading.cpp @@ -822,17 +822,24 @@ CondBr->getSuccessor(ToRemove)->removePredecessor(BB, true); BranchInst::Create(CondBr->getSuccessor(ToKeep), CondBr); CondBr->eraseFromParent(); - if (CondCmp->use_empty()) - CondCmp->eraseFromParent(); - else if (CondCmp->getParent() == BB) { - // If the fact we just learned is true for all uses of the - // condition, replace it with a constant value + + // Now, see if we can eagerly update any other uses. WARNING: we used a + // context instruction at the end of the current basic block, so the + // facts LVI returned may not be true before that point. (i.e. we may + // have a guard or assume part way through the block.) Thus, we can + // not reason about any use which is not dominated by the context + // instruction. Given we don't have dom-tree here, we're restricted to + // only handling cases where dominance can be trivially established + // from the definition of SSA. + if (!CondCmp->use_empty() && + CondCmp->getParent() == BB) { auto *CI = Ret == LazyValueInfo::True ? ConstantInt::getTrue(CondCmp->getType()) : ConstantInt::getFalse(CondCmp->getType()); - CondCmp->replaceAllUsesWith(CI); - CondCmp->eraseFromParent(); + replaceNonLocalUsesWith(CondCmp, CI); } + if (CondCmp->use_empty()) + CondCmp->eraseFromParent(); return true; } } Index: test/Transforms/JumpThreading/assume.ll =================================================================== --- test/Transforms/JumpThreading/assume.ll +++ test/Transforms/JumpThreading/assume.ll @@ -56,8 +56,50 @@ ret i32 %retval.0 } +@g = external global i32 + +; Check that we do prove a fact using an assume within the block and +; that we *don't* use circular logic to remove the assume. +; CHECK-LABEL: @local_assume +; CHECK: %notnull = icmp ne i32* %array, null +; CHECK-NEXT: call void @llvm.assume(i1 %notnull) +; CHECK-NEXT: ret void +define void @local_assume(i32* %array) { + %notnull = icmp ne i32* %array, null + call void @llvm.assume(i1 %notnull) + br i1 %notnull, label %normal, label %error + +normal: + ret void + +error: + store atomic i32 0, i32* @g unordered, align 4 + ret void +} + +; Check that we do prove a fact using an assume within the block and +; that we *don't* use circular logic to remove the guard. +; CHECK-LABEL: @local_guard +; CHECK: %notnull = icmp ne i32* %array, null +; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %notnull) [ "deopt"(i32 0) ] +; CHECK-NEXT: ret void + +define void @local_guard(i32* %array) { + %notnull = icmp ne i32* %array, null + call void (i1, ...) @llvm.experimental.guard(i1 %notnull) ["deopt" (i32 0)] + br i1 %notnull, label %normal, label %error + +normal: + ret void + +error: + store atomic i32 0, i32* @g unordered, align 4 + ret void +} + ; Function Attrs: nounwind declare void @llvm.assume(i1) #1 +declare void @llvm.experimental.guard(i1 %cnd, ...) declare void @bar(...)