diff --git a/llvm/lib/Transforms/Scalar/JumpThreading.cpp b/llvm/lib/Transforms/Scalar/JumpThreading.cpp --- a/llvm/lib/Transforms/Scalar/JumpThreading.cpp +++ b/llvm/lib/Transforms/Scalar/JumpThreading.cpp @@ -2003,6 +2003,39 @@ void JumpThreadingPass::UpdateSSA( BasicBlock *BB, BasicBlock *NewBB, DenseMap &ValueMapping) { + // Don't create PHI nodes with values from is_constant intrinsics. Code gated + // by these intrinsics sometimes rely upon their evaluation to DCE invalid + // paths. Combining them into PHI nodes complicates the evaluation. + SmallVector IsConstantIntrs; + for (Instruction &I : *BB) { + if (!isa(I) || + cast(I).getIntrinsicID() != Intrinsic::is_constant) + continue; + + // Scan all uses of this instruction to see if it is used outside of its + // block. + for (Use &U : I.uses()) { + Instruction *User = cast(U.getUser()); + if (PHINode *UserPN = dyn_cast(User)) { + if (UserPN->getIncomingBlock(U) == BB) + continue; + } else if (User->getParent() == BB) { + continue; + } + + IsConstantIntrs.push_back(&I); + break; + } + } + + for (auto *II : IsConstantIntrs) { + Constant *Res = isa(II->getOperand(0)) + ? ConstantInt::getTrue(II->getType()) + : ConstantInt::getFalse(II->getType()); + II->replaceAllUsesWith(Res); + II->eraseFromParent(); + } + // If there were values defined in BB that are used outside the block, then we // now have to update all uses of the value to use either the original value, // the cloned value, or some PHI derived value. This can require arbitrary @@ -2332,7 +2365,7 @@ // And finally, do it! LLVM_DEBUG(dbgs() << " Threading edge from '" << PredBB->getName() << "' to '" << SuccBB->getName() - << ", across block:\n " << *BB << "\n"); + << "', across block:\n " << *BB << "\n"); if (DTU->hasPendingDomTreeUpdates()) LVI->disableDT(); diff --git a/llvm/test/Transforms/JumpThreading/is_constant.ll b/llvm/test/Transforms/JumpThreading/is_constant.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/JumpThreading/is_constant.ll @@ -0,0 +1,39 @@ +; RUN: opt -jump-threading -S -verify < %s | FileCheck %s + +; CHECK-LABEL: define void @test1( +; CHECK-LABEL: if.end18: +; CHECK-NOT: call i1 @llvm.is.constant.i64 +define void @test1() { +entry: + %conv = trunc i64 undef to i32 + %conv8 = ashr exact i64 undef, 32 + %cmp9 = icmp ugt i64 %conv8, 24 + br i1 %cmp9, label %if.then11, label %if.end18 + +if.then11: ; preds = %entry + br label %if.end18 + +if.end18: ; preds = %if.then11, %entry + %len.0 = phi i32 [ 24, %if.then11 ], [ %conv, %entry ] + %cmp3.i.i70 = icmp ugt i32 %len.0, 24 + %0 = call i1 @llvm.is.constant.i64(i64 undef) #1 + br i1 %cmp3.i.i70, label %if.then.i.i71, label %if.end12.i.i74 + +if.then.i.i71: ; preds = %if.end18 + unreachable + +if.end12.i.i74: ; preds = %if.end18 + br i1 %0, label %if.else.i.i, label %if.then7.i.i + +if.then7.i.i: ; preds = %if.end12.i.i74 + ret void + +if.else.i.i: ; preds = %if.end12.i.i74 + unreachable +} + +; Function Attrs: nounwind readnone willreturn +declare i1 @llvm.is.constant.i64(i64) #0 + +attributes #0 = { nounwind readnone willreturn } +attributes #1 = { nounwind }