From: Philip Reames Date: Fri, 26 Feb 2021 18:18:56 +0000 (-0800) Subject: Add a helper for matching simple recurrence cycles X-Git-Tag: llvmorg-14-init~13931 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=8020be0b8b57e0d29d93f0a4a5b2e9bbfd2242e7;p=platform%2Fupstream%2Fllvm.git Add a helper for matching simple recurrence cycles This helper came up in another review, and I've got about 4 different patches with copies of this copied into it. Time to precommit the routine. :) --- diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h index 1dbb8bf..93a8464 100644 --- a/llvm/include/llvm/Analysis/ValueTracking.h +++ b/llvm/include/llvm/Analysis/ValueTracking.h @@ -748,6 +748,16 @@ constexpr unsigned MaxAnalysisRecursionDepth = 6; std::pair canConvertToMinOrMaxIntrinsic(ArrayRef VL); + /// Attempt to match a simple recurrence cycle of the form: + /// (using SCEV's notation) + /// In IR, this might look like: + /// %iv = phi Ty [%Start, %Entry], [%Inc, %backedge] + /// %inc = binop %iv, %step + /// NOTE: This is intentional simple. If you want the ability to analyze + /// non-trivial loop conditons, see ScalarEvolution instead. + bool matchSimpleRecurrence(PHINode *P, BinaryOperator *&BO, + Value *&Start, Value *&Step); + /// Return true if RHS is known to be implied true by LHS. Return false if /// RHS is known to be implied false by LHS. Otherwise, return None if no /// implication can be made. diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index 520c7f9..b93d70a 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -6053,6 +6053,70 @@ llvm::canConvertToMinOrMaxIntrinsic(ArrayRef VL) { return {Intrinsic::not_intrinsic, false}; } +bool llvm::matchSimpleRecurrence(PHINode *P, BinaryOperator *&BO, + Value *&Start, Value *&Step) { + // Handle the case of a simple two-predecessor recurrence PHI. + // There's a lot more that could theoretically be done here, but + // this is sufficient to catch some interesting cases. + if (P->getNumIncomingValues() != 2) + return false; + + for (unsigned i = 0; i != 2; ++i) { + Value *L = P->getIncomingValue(i); + Value *R = P->getIncomingValue(!i); + Operator *LU = dyn_cast(L); + if (!LU) + continue; + unsigned Opcode = LU->getOpcode(); + + switch (Opcode) { + default: + continue; + case Instruction::LShr: + case Instruction::AShr: + case Instruction::Shl: { + Value *LL = LU->getOperand(0); + Value *LR = LU->getOperand(1); + // Find a recurrence. + if (LL == P) + L = LR; + else + continue; // Check for recurrence with L and R flipped. + + break; // Match! + } + + // TODO: Expand list -- xor, mul, div, gep, uaddo, etc.. + case Instruction::Add: + case Instruction::Sub: + case Instruction::And: + case Instruction::Or: + case Instruction::Mul: { + Value *LL = LU->getOperand(0); + Value *LR = LU->getOperand(1); + // Find a recurrence. + if (LL == P) + L = LR; + else if (LR == P) + L = LL; + else + continue; // Check for recurrence with L and R flipped. + + break; // Match! + } + }; + + // We have matched a recurrence of the form: + // %iv = [R, %entry], [%iv.next, %backedge] + // %iv.next = binop %iv, L + BO = cast(LU); + Start = R; + Step = L; + return true; + } + return false; +} + /// Return true if "icmp Pred LHS RHS" is always true. static bool isTruePredicate(CmpInst::Predicate Pred, const Value *LHS, const Value *RHS, const DataLayout &DL,