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 @@ -2387,6 +2387,58 @@ return VScaleVal_match(DL); } +template +struct LogicalOp_match { + LHS L; + RHS R; + + LogicalOp_match(const LHS &L, const RHS &R) : L(L), R(R) {} + + template bool match(T *V) { + if (auto *I = dyn_cast(V)) { + if (!I->getType()->isIntOrIntVectorTy(1)) + return false; + + if (I->getOpcode() == Opcode && L.match(I->getOperand(0)) && + R.match(I->getOperand(1))) + return true; + + if (auto *SI = dyn_cast(I)) { + if (Opcode == Instruction::And) { + if (const auto *C = dyn_cast(SI->getFalseValue())) + if (C->isNullValue() && L.match(SI->getCondition()) && + R.match(SI->getTrueValue())) + return true; + } else { + assert(Opcode == Instruction::Or); + if (const auto *C = dyn_cast(SI->getTrueValue())) + if (C->isOneValue() && L.match(SI->getCondition()) && + R.match(SI->getFalseValue())) + return true; + } + } + } + + return false; + } +}; + +/// Matches L && R either in the form of L & R or L ? R : false. +/// Note that the latter form is poison-blocking. +template +inline LogicalOp_match +m_LogicalAnd(const LHS &L, const RHS &R) { + return LogicalOp_match(L, R); +} + +/// Matches L || R either in the form of L | R or L ? true : R. +/// Note that the latter form is poison-blocking. +template +inline LogicalOp_match +m_LogicalOr(const LHS &L, const RHS &R) { + return LogicalOp_match(L, R); +} + } // end namespace PatternMatch } // end namespace llvm diff --git a/llvm/lib/Analysis/LazyValueInfo.cpp b/llvm/lib/Analysis/LazyValueInfo.cpp --- a/llvm/lib/Analysis/LazyValueInfo.cpp +++ b/llvm/lib/Analysis/LazyValueInfo.cpp @@ -1205,22 +1205,20 @@ // true dest path both of the conditions hold. Similarly for conditions of // the form (cond1 || cond2), we know that on the false dest path neither // condition holds. - BinaryOperator *BO = dyn_cast(Cond); - if (!BO || (isTrueDest && BO->getOpcode() != BinaryOperator::And) || - (!isTrueDest && BO->getOpcode() != BinaryOperator::Or)) + Value *L, *R; + if (isTrueDest ? !match(Cond, m_LogicalAnd(m_Value(L), m_Value(R))) + : !match(Cond, m_LogicalOr(m_Value(L), m_Value(R)))) return ValueLatticeElement::getOverdefined(); // Prevent infinite recursion if Cond references itself as in this example: // Cond: "%tmp4 = and i1 %tmp4, undef" // BL: "%tmp4 = and i1 %tmp4, undef" // BR: "i1 undef" - Value *BL = BO->getOperand(0); - Value *BR = BO->getOperand(1); - if (BL == Cond || BR == Cond) + if (L == Cond || R == Cond) return ValueLatticeElement::getOverdefined(); - return intersect(getValueFromCondition(Val, BL, isTrueDest, Visited), - getValueFromCondition(Val, BR, isTrueDest, Visited)); + return intersect(getValueFromCondition(Val, L, isTrueDest, Visited), + getValueFromCondition(Val, R, isTrueDest, Visited)); } static ValueLatticeElement diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/basic.ll b/llvm/test/Transforms/CorrelatedValuePropagation/basic.ll --- a/llvm/test/Transforms/CorrelatedValuePropagation/basic.ll +++ b/llvm/test/Transforms/CorrelatedValuePropagation/basic.ll @@ -1069,10 +1069,8 @@ ; CHECK-NEXT: [[AND:%.*]] = select i1 [[CMP1]], i1 [[CMP2]], i1 false ; CHECK-NEXT: br i1 [[AND]], label [[GUARD:%.*]], label [[EXIT:%.*]] ; CHECK: guard: -; CHECK-NEXT: [[C1:%.*]] = icmp sgt i32 [[A]], 20 -; CHECK-NEXT: store i1 [[C1]], i1* [[P:%.*]], align 1 -; CHECK-NEXT: [[C2:%.*]] = icmp slt i32 [[A]], -20 -; CHECK-NEXT: store i1 [[C2]], i1* [[P]], align 1 +; CHECK-NEXT: store i1 false, i1* [[P:%.*]], align 1 +; CHECK-NEXT: store i1 false, i1* [[P]], align 1 ; CHECK-NEXT: br label [[EXIT]] ; CHECK: exit: ; CHECK-NEXT: ret void @@ -1168,10 +1166,8 @@ ; CHECK-NEXT: [[OR:%.*]] = select i1 [[CMP1]], i1 true, i1 [[CMP2]] ; CHECK-NEXT: br i1 [[OR]], label [[EXIT:%.*]], label [[GUARD:%.*]] ; CHECK: guard: -; CHECK-NEXT: [[C1:%.*]] = icmp sgt i32 [[A]], 20 -; CHECK-NEXT: store i1 [[C1]], i1* [[P:%.*]], align 1 -; CHECK-NEXT: [[C2:%.*]] = icmp slt i32 [[A]], -20 -; CHECK-NEXT: store i1 [[C2]], i1* [[P]], align 1 +; CHECK-NEXT: store i1 false, i1* [[P:%.*]], align 1 +; CHECK-NEXT: store i1 false, i1* [[P]], align 1 ; CHECK-NEXT: br label [[EXIT]] ; CHECK: exit: ; CHECK-NEXT: ret void