[llvm] [HashRecognize] Rewrite arePHIsIntertwined (PR #144878)

Piotr Fusik via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 23 06:31:53 PDT 2025


================
@@ -497,45 +497,35 @@ CRCTable HashRecognize::genSarwateTable(const APInt &GenPoly,
   return Table;
 }
 
-/// Checks if \p Reference is reachable from \p Needle on the use-def chain, and
-/// that there are no stray PHI nodes while digging the use-def chain. \p
-/// BOToMatch is a CRC peculiarity: at least one of the Users of Needle needs to
-/// match this OpCode, which is XOR for CRC.
-static bool arePHIsIntertwined(
-    const PHINode *Needle, const PHINode *Reference, const Loop &L,
-    Instruction::BinaryOps BOToMatch = Instruction::BinaryOpsEnd) {
-  // Initialize the worklist with Users of the Needle.
-  SmallVector<const Instruction *> Worklist;
-  for (const User *U : Needle->users()) {
-    if (auto *UI = dyn_cast<Instruction>(U))
-      if (L.contains(UI))
-        Worklist.push_back(UI);
-  }
-
-  // BOToMatch is usually XOR for CRC.
-  if (BOToMatch != Instruction::BinaryOpsEnd) {
-    if (count_if(Worklist, [BOToMatch](const Instruction *I) {
-          return I->getOpcode() == BOToMatch;
-        }) != 1)
-      return false;
-  }
-
-  while (!Worklist.empty()) {
-    const Instruction *I = Worklist.pop_back_val();
-
-    // Since Needle is never pushed onto the Worklist, I must either be the
-    // Reference PHI node (in which case we're done), or a stray PHI node (in
-    // which case we abort).
-    if (isa<PHINode>(I))
-      return I == Reference;
-
-    for (const Use &U : I->operands())
-      if (auto *UI = dyn_cast<Instruction>(U))
-        // Don't push Needle back onto the Worklist.
-        if (UI != Needle && L.contains(UI))
-          Worklist.push_back(UI);
-  }
-  return false;
+/// Checks that \p Needle and \p Reference are used together in a BinaryOperator
+/// with opcode \p BOToMatch, which is a recurrence over both, ignoring zext and
+/// trunc. In other words, it checks for the following pattern:
+///
+/// loop:
+///   %needle = phi [_, %entry], [%needle.next, %loop]
+///   %reference = phi [_, %entry], [%reference.next, %loop]
+///   ...
+///   _ = BOTOMatch ((trunc|zext|self) %needle) ((trunc|zext|self) %reference)
+///
+///  where at least one cast is self.
+///
+/// \p BOToMatch is XOR in the case of CRC.
+static bool arePHIsIntertwined(const PHINode *Needle, const PHINode *Reference,
+                               const Loop &L,
+                               Instruction::BinaryOps BOToMatch) {
+  return any_of(ArrayRef({Needle, Reference}), [&](const PHINode *S) {
+    return count_if(S->users(), [&](const User *U) {
+             auto *BO = dyn_cast<BinaryOperator>(U);
+             if (!BO || BO->getOpcode() != BOToMatch)
+               return false;
+             return all_of(BO->operands(), [Needle, Reference](const Use &U) {
+               return match(
+                   U.get(),
+                   m_CombineOr(m_ZExtOrTruncOrSelf(m_Specific(Reference)),
+                               m_ZExtOrTruncOrSelf(m_Specific(Needle))));
+             });
+           }) == 1;
+  });
----------------
pfusik wrote:

I find these multiple nestings of lambdas hard to understand. How about:

```cpp
static bool isXoredWith(Value *L, Value *R) {
  return count_if(L->users(), [L, R](const User *U) {
      return match(U.get(),
                   m_c_Xor(m_Specific(L),
                           m_CombineOr(m_ZExtOrSelf(m_Specific(R)),
                                       m_Trunc(m_Specific(R)))));
    }) == 1;
}

static bool arePHIsIntertwined(const PHINode *Needle, const PHINode *Reference) {
  return isXoredWith(Needle, Reference) || isXoredWith(Reference, Needle);
}
```

https://github.com/llvm/llvm-project/pull/144878


More information about the llvm-commits mailing list