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/include/llvm/IR/PatternMatch.h b/llvm/include/llvm/IR/PatternMatch.h --- a/llvm/include/llvm/IR/PatternMatch.h +++ b/llvm/include/llvm/IR/PatternMatch.h @@ -708,6 +708,10 @@ inline bind_ty m_BinOp(BinaryOperator *&I) { return I; } /// Match a with overflow intrinsic, capturing it if we match. inline bind_ty m_WithOverflowInst(WithOverflowInst *&I) { return I; } +inline bind_ty +m_WithOverflowInst(const WithOverflowInst *&I) { + return I; +} /// Match a Constant, capturing the value if we match. inline bind_ty m_Constant(Constant *&C) { return C; } @@ -2314,9 +2318,13 @@ ExtractValue_match(const Opnd_t &V) : Val(V) {} template bool match(OpTy *V) { - if (auto *I = dyn_cast(V)) - return I->getNumIndices() == 1 && I->getIndices()[0] == Ind && - Val.match(I->getAggregateOperand()); + if (auto *I = dyn_cast(V)) { + // If Ind is -1, don't inspect indices + if (Ind != -1 && + !(I->getNumIndices() == 1 && I->getIndices()[0] == (unsigned)Ind)) + return false; + return Val.match(I->getAggregateOperand()); + } return false; } }; @@ -2328,6 +2336,13 @@ return ExtractValue_match(V); } +/// Match an ExtractValue instruction with any index. +/// For example m_ExtractValue(...) +template +inline ExtractValue_match<-1, Val_t> m_ExtractValue(const Val_t &V) { + return ExtractValue_match<-1, Val_t>(V); +} + /// Matcher for a single index InsertValue instruction. template struct InsertValue_match { T0 Op0; 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 @@ -4852,11 +4852,19 @@ if (Depth >= MaxDepth) 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); - }); + if (const auto *I = dyn_cast(V)) { + 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. (e.g., add_with_overflow) + const WithOverflowInst *II; + if (match(I, m_ExtractValue(m_WithOverflowInst(II))) && + match(ValAssumedPoison, m_ExtractValue(m_Specific(II)))) + 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