diff --git a/lib/Analysis/ValueTracking.cpp b/lib/Analysis/ValueTracking.cpp index 39d8f9b9509..e5c3f3f96e3 100644 --- a/lib/Analysis/ValueTracking.cpp +++ b/lib/Analysis/ValueTracking.cpp @@ -4887,6 +4887,12 @@ static bool canCreateUndefOrPoison(const Operator *Op, bool PoisonOnly) { switch (II->getIntrinsicID()) { // TODO: Add more intrinsics. case Intrinsic::ctpop: + case Intrinsic::sadd_with_overflow: + case Intrinsic::ssub_with_overflow: + case Intrinsic::smul_with_overflow: + case Intrinsic::uadd_with_overflow: + case Intrinsic::usub_with_overflow: + case Intrinsic::umul_with_overflow: return false; } } @@ -5214,9 +5220,25 @@ bool llvm::propagatesPoison(const Operator *I) { case Instruction::Freeze: case Instruction::Select: case Instruction::PHI: - case Instruction::Call: case Instruction::Invoke: return false; + case Instruction::Call: + if (auto *II = dyn_cast(I)) { + switch (II->getIntrinsicID()) { + // TODO: Add more intrinsics. + case Intrinsic::sadd_with_overflow: + case Intrinsic::ssub_with_overflow: + case Intrinsic::smul_with_overflow: + case Intrinsic::uadd_with_overflow: + case Intrinsic::usub_with_overflow: + case Intrinsic::umul_with_overflow: + // If an input is a vector containing a poison element, the + // two output vectors (calculated results, overflow bits)' + // corresponding lanes are poison. + return true; + } + } + return false; case Instruction::ICmp: case Instruction::FCmp: case Instruction::GetElementPtr: diff --git a/unittests/Analysis/ValueTrackingTest.cpp b/unittests/Analysis/ValueTrackingTest.cpp index 18fb1545a94..93bb2635b24 100644 --- a/unittests/Analysis/ValueTrackingTest.cpp +++ b/unittests/Analysis/ValueTrackingTest.cpp @@ -805,9 +805,16 @@ TEST_F(ValueTrackingTest, ComputeNumSignBits_Shuffle_Pointers) { } TEST(ValueTracking, propagatesPoison) { - std::string AsmHead = "declare i32 @g(i32)\n" - "define void @f(i32 %x, i32 %y, float %fx, float %fy, " - "i1 %cond, i8* %p) {\n"; + std::string AsmHead = + "declare i32 @g(i32)\n" + "declare {i32, i1} @llvm.sadd.with.overflow.i32(i32 %a, i32 %b)\n" + "declare {i32, i1} @llvm.ssub.with.overflow.i32(i32 %a, i32 %b)\n" + "declare {i32, i1} @llvm.smul.with.overflow.i32(i32 %a, i32 %b)\n" + "declare {i32, i1} @llvm.uadd.with.overflow.i32(i32 %a, i32 %b)\n" + "declare {i32, i1} @llvm.usub.with.overflow.i32(i32 %a, i32 %b)\n" + "declare {i32, i1} @llvm.umul.with.overflow.i32(i32 %a, i32 %b)\n" + "define void @f(i32 %x, i32 %y, float %fx, float %fy, " + "i1 %cond, i8* %p) {\n"; std::string AsmTail = " ret void\n}"; // (propagates poison?, IR instruction) SmallVector, 32> Data = { @@ -826,7 +833,13 @@ TEST(ValueTracking, propagatesPoison) { {true, "urem i32 %x, %y"}, {true, "sdiv exact i32 %x, %y"}, {true, "srem i32 %x, %y"}, - {false, "call i32 @g(i32 %x)"}}; + {false, "call i32 @g(i32 %x)"}, + {true, "call {i32, i1} @llvm.sadd.with.overflow.i32(i32 %x, i32 %y)"}, + {true, "call {i32, i1} @llvm.ssub.with.overflow.i32(i32 %x, i32 %y)"}, + {true, "call {i32, i1} @llvm.smul.with.overflow.i32(i32 %x, i32 %y)"}, + {true, "call {i32, i1} @llvm.uadd.with.overflow.i32(i32 %x, i32 %y)"}, + {true, "call {i32, i1} @llvm.usub.with.overflow.i32(i32 %x, i32 %y)"}, + {true, "call {i32, i1} @llvm.umul.with.overflow.i32(i32 %x, i32 %y)"}}; std::string AssemblyStr = AsmHead; for (auto &Itm : Data) @@ -992,6 +1005,12 @@ TEST(ValueTracking, canCreatePoisonOrUndef) { std::string AsmHead = "@s = external dso_local global i32, align 1\n" "declare i32 @g(i32)\n" + "declare {i32, i1} @llvm.sadd.with.overflow.i32(i32 %a, i32 %b)\n" + "declare {i32, i1} @llvm.ssub.with.overflow.i32(i32 %a, i32 %b)\n" + "declare {i32, i1} @llvm.smul.with.overflow.i32(i32 %a, i32 %b)\n" + "declare {i32, i1} @llvm.uadd.with.overflow.i32(i32 %a, i32 %b)\n" + "declare {i32, i1} @llvm.usub.with.overflow.i32(i32 %a, i32 %b)\n" + "declare {i32, i1} @llvm.umul.with.overflow.i32(i32 %a, i32 %b)\n" "define void @f(i32 %x, i32 %y, float %fx, float %fy, i1 %cond, " "<4 x i32> %vx, <4 x i32> %vx2, %svx, i8* %p) {\n"; std::string AsmTail = " ret void\n}"; @@ -1053,7 +1072,19 @@ TEST(ValueTracking, canCreatePoisonOrUndef) { {{true, false}, "ashr <4 x i32> %vx, select (i1 icmp sgt (i32 ptrtoint (i32* @s to " "i32), i32 1), <4 x i32> zeroinitializer, <4 x i32> )"}}; + "2, i32 3>)"}, + {{false, false}, + "call {i32, i1} @llvm.sadd.with.overflow.i32(i32 %x, i32 %y)"}, + {{false, false}, + "call {i32, i1} @llvm.ssub.with.overflow.i32(i32 %x, i32 %y)"}, + {{false, false}, + "call {i32, i1} @llvm.smul.with.overflow.i32(i32 %x, i32 %y)"}, + {{false, false}, + "call {i32, i1} @llvm.uadd.with.overflow.i32(i32 %x, i32 %y)"}, + {{false, false}, + "call {i32, i1} @llvm.usub.with.overflow.i32(i32 %x, i32 %y)"}, + {{false, false}, + "call {i32, i1} @llvm.umul.with.overflow.i32(i32 %x, i32 %y)"}}; std::string AssemblyStr = AsmHead; for (auto &Itm : Data)