forked from OSchip/llvm-project
[ValueTracking] Add with.overflow intrinsics to poison analysis functions
This is a patch teaching ValueTracking that `s/u*.with.overflow` intrinsics do not create undef/poison and they propagate poison. I couldn't write a nice example like the one with ctpop; ValueTrackingTest.cpp were simply updated to check these instead. This patch helps reducing regression while fixing https://llvm.org/pr49688 . Reviewed By: nikic Differential Revision: https://reviews.llvm.org/D99671
This commit is contained in:
parent
ae7b1e8823
commit
df0b97dab0
|
@ -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<IntrinsicInst>(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:
|
||||
|
|
|
@ -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<std::pair<bool, std::string>, 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, <vscale x 4 x i32> %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> <i32 0, i32 1, i32 "
|
||||
"2, i32 3>)"}};
|
||||
"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)
|
||||
|
|
Loading…
Reference in New Issue