From: Juneyoung Lee Date: Thu, 18 Feb 2021 03:38:40 +0000 (+0900) Subject: [ValueTracking] Improve impliesPoison X-Git-Tag: llvmorg-14-init~14542 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=aacf7878bc83a5231d2768f8dd69e98b7607366f;p=platform%2Fupstream%2Fllvm.git [ValueTracking] Improve impliesPoison This patch improves ValueTracking's impliesPoison(V1, V2) to do this reasoning: ``` %res = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b) %overflow = extractvalue { i64, i1 } %res, 1 %mul = extractvalue { i64, i1 } %res, 0 ; If %mul is poison, %overflow is also poison, and vice versa. ``` This improvement leads to supporting this optimization under `-instcombine-unsafe-select-transform=0`: ``` define i1 @test2_logical(i64 %a, i64 %b, i64* %ptr) { ; CHECK-LABEL: @test2_logical( ; CHECK-NEXT: [[MUL:%.*]] = mul i64 [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[A]], 0 ; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[B]], 0 ; CHECK-NEXT: [[OVERFLOW_1:%.*]] = and i1 [[TMP1]], [[TMP2]] ; CHECK-NEXT: [[NEG:%.*]] = sub i64 0, [[MUL]] ; CHECK-NEXT: store i64 [[NEG]], i64* [[PTR:%.*]], align 8 ; CHECK-NEXT: ret i1 [[OVERFLOW_1]] ; %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b) %overflow = extractvalue { i64, i1 } %res, 1 %mul = extractvalue { i64, i1 } %res, 0 %cmp = icmp ne i64 %mul, 0 %overflow.1 = select i1 %overflow, i1 true, i1 %cmp %neg = sub i64 0, %mul store i64 %neg, i64* %ptr, align 8 ret i1 %overflow.1 } ``` Previously, this didn't happen because the flag prevented `select i1 %overflow, i1 true, i1 %cmp` from being `or i1 %overflow, %cmp`. Note that the select -> or conversion happens only when `impliesPoison(%cmp, %overflow)` returns true. This improvement allows `impliesPoison` to do the reasoning. Reviewed By: nikic Differential Revision: https://reviews.llvm.org/D96929 --- diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h index 25dcd80..1dbb8bf 100644 --- a/llvm/include/llvm/Analysis/ValueTracking.h +++ b/llvm/include/llvm/Analysis/ValueTracking.h @@ -582,6 +582,8 @@ constexpr unsigned MaxAnalysisRecursionDepth = 6; /// 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 index 166ad23..0895002 100644 --- a/llvm/include/llvm/IR/PatternMatch.h +++ b/llvm/include/llvm/IR/PatternMatch.h @@ -708,6 +708,10 @@ inline bind_ty m_UnOp(UnaryOperator *&I) { return I; } 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 @@ template struct ExtractValue_match { 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 @@ inline ExtractValue_match m_ExtractValue(const Val_t &V) { 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 index 600509f..0491941 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -4870,11 +4870,19 @@ static bool directlyImpliesPoison(const Value *ValAssumedPoison, 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 index 8fa6593..9cf6921 100644 --- 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