diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h --- a/llvm/include/llvm/Analysis/ValueTracking.h +++ b/llvm/include/llvm/Analysis/ValueTracking.h @@ -582,6 +582,8 @@ /// poison. /// Formally, given I = `r = op v1 v2 .. vN`, propagatesPoison returns true /// if, for all i, r is evaluated to poison or op raises UB if vi = poison. + /// If vi is a vector or an aggregate and r is a single value, any poison + /// element in vi should make r poison or raise UB. /// To filter out operands that raise UB on poison, you can use /// getGuaranteedNonPoisonOp. bool propagatesPoison(const Operator *I); 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 @@ -4843,6 +4843,28 @@ return ::canCreateUndefOrPoison(Op, /*PoisonOnly=*/true); } +// Given V of an aggregate type, return true if V's elements are all poison or +// not poison. +static bool isAllPoisonOrNot(const Value *V) { + assert(V->getType()->isAggregateType()); + + auto *II = dyn_cast(V); + if (!II) + return false; + + switch(II->getIntrinsicID()) { + 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 true; + default: + return false; + } +} + static bool directlyImpliesPoison(const Value *ValAssumedPoison, const Value *V, unsigned Depth) { if (ValAssumedPoison == V) @@ -4853,10 +4875,21 @@ return false; const auto *I = dyn_cast(V); - if (I && propagatesPoison(cast(I))) { - return any_of(I->operands(), [=](const Value *Op) { - return directlyImpliesPoison(ValAssumedPoison, Op, Depth + 1); - }); + const auto *I2 = dyn_cast(ValAssumedPoison); + if (I) { + if (propagatesPoison(cast(I))) + return any_of(I->operands(), [=](const Value *Op) { + return directlyImpliesPoison(ValAssumedPoison, Op, Depth + 1); + }); + + // V = extractvalue V0, idx + // V2 = extractvalue V0, idx2 + // V0's elements are all poison or not + if (isa(I) && isa(ValAssumedPoison)) { + if (I->getOperand(0) == I2->getOperand(0) && + isAllPoisonOrNot(I->getOperand(0))) + return true; + } } return false; } diff --git a/llvm/test/Transforms/InstCombine/umul-sign-check.ll b/llvm/test/Transforms/InstCombine/umul-sign-check.ll --- a/llvm/test/Transforms/InstCombine/umul-sign-check.ll +++ b/llvm/test/Transforms/InstCombine/umul-sign-check.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -instcombine -S %s | FileCheck %s +; RUN: opt -instcombine -instcombine-unsafe-select-transform=0 -S %s | FileCheck %s ; Check that we simplify llvm.umul.with.overflow, if the overflow check is ; weakened by or (icmp ne %res, 0) %overflow. This is generated by code using