From 6f01cb91d763f740339683e1bde029e9f9f3bdf4 Mon Sep 17 00:00:00 2001 From: Justin Lebar Date: Thu, 27 Apr 2023 23:31:26 -0700 Subject: [PATCH] Handle `select` in programUndefinedIfPoison. If both the true and false operands of a `select` are poison, then the `select` is poison. Differential Revision: https://reviews.llvm.org/D149427 --- llvm/lib/Analysis/ValueTracking.cpp | 11 ++++++++++- llvm/unittests/Analysis/ValueTrackingTest.cpp | 14 ++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index 57a6533..85361e5 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -6707,7 +6707,7 @@ bool llvm::isGuaranteedNotToBePoison(const Value *V, AssumptionCache *AC, 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 @@ static bool programUndefinedIfUndefOrPoison(const Value *V, 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 index 72d6387..6a8f468 100644 --- a/llvm/unittests/Analysis/ValueTrackingTest.cpp +++ b/llvm/unittests/Analysis/ValueTrackingTest.cpp @@ -982,6 +982,20 @@ TEST_F(ValueTrackingTest, programUndefinedIfPoison) { 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" -- 2.7.4