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 @@ -6707,7 +6707,7 @@ return ::isGuaranteedNotToBeUndefOrPoison(V, AC, CtxI, DT, Depth, true); } -/// Return true if undefined behavior would provable be executed on the path to +/// Return true if undefined behavior would provably be executed on the path to /// OnPathTo if Root produced a posion result. Note that this doesn't say /// anything about whether OnPathTo is actually executed or whether Root is /// actually poison. This can be used to assess whether a new use of Root can @@ -7041,6 +7041,15 @@ break; } } + + // Special handling for select, which returns poison if its operand 0 is + // poison (handled in the loop above) *or* if both its true/false operands + // are poison (handled here). + if (I.getOpcode() == Instruction::Select && + YieldsPoison.count(I.getOperand(1)) && + YieldsPoison.count(I.getOperand(2))) { + YieldsPoison.insert(&I); + } } BB = BB->getSingleSuccessor(); diff --git a/llvm/unittests/Analysis/ValueTrackingTest.cpp b/llvm/unittests/Analysis/ValueTrackingTest.cpp --- a/llvm/unittests/Analysis/ValueTrackingTest.cpp +++ b/llvm/unittests/Analysis/ValueTrackingTest.cpp @@ -982,6 +982,20 @@ EXPECT_EQ(programUndefinedIfPoison(A), true); } +TEST_F(ValueTrackingTest, programUndefinedIfPoisonSelect) { + parseAssembly("declare i32 @any_num()" + "define void @test(i1 %Cond) {\n" + " %A = call i32 @any_num()\n" + " %B = add i32 %A, 1\n" + " %C = select i1 %Cond, i32 %A, i32 %B\n" + " udiv i32 1, %C" + " ret void\n" + "}\n"); + // If A is poison, B is also poison, and therefore C is poison regardless of + // the value of %Cond. + EXPECT_EQ(programUndefinedIfPoison(A), true); +} + TEST_F(ValueTrackingTest, programUndefinedIfUndefOrPoison) { parseAssembly("declare i32 @any_num()" "define void @test(i32 %mask) {\n"