[llvm] [LoopIdiom] Use HashRecognize to optimize CRC (PR #143208)

Piotr Fusik via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 9 00:56:37 PDT 2025


================
@@ -1473,6 +1494,146 @@ bool LoopIdiomRecognize::avoidLIRForMultiBlockLoop(bool IsMemset,
   return false;
 }
 
+bool LoopIdiomRecognize::optimizeCRCLoop(const PolynomialInfo &Info) {
+  // We currently only optimize CRC loops with TC a multiple of 8 with a table
+  // lookup: the table-lookup can be improved using target-specific
+  // instructions.
+  if (Info.TripCount % 8 != 0)
+    return false;
+
+  // First, create a new GlobalVariable corresponding to the
+  // Sarwate-lookup-table.
+  Type *CRCTy = Info.LHS->getType();
+  unsigned CRCBW = CRCTy->getIntegerBitWidth();
+  std::array<Constant *, 256> CRCConstants;
+  transform(Info.SarwateTable, CRCConstants.begin(),
+            [CRCTy](const APInt &E) { return ConstantInt::get(CRCTy, E); });
+  Constant *ConstArray =
+      ConstantArray::get(ArrayType::get(CRCTy, 256), CRCConstants);
+  Module &M = *CurLoop->getHeader()->getModule();
+  GlobalVariable *GV =
+      new GlobalVariable(M, ConstArray->getType(), true,
+                         GlobalValue::PrivateLinkage, ConstArray, ".crctable");
+
+  PHINode *IV = CurLoop->getCanonicalInductionVariable();
+  Type *IVTy = IV->getType();
+  SmallVector<PHINode *, 2> Cleanup;
+
+  // Next, mark all PHIs for removal except IV.
+  {
+    for (PHINode &PN : CurLoop->getHeader()->phis()) {
+      if (&PN == IV)
+        continue;
+      PN.replaceAllUsesWith(PoisonValue::get(PN.getType()));
+      Cleanup.push_back(&PN);
+    }
+  }
+
+  // Next, fix up the trip count.
+  {
+    unsigned NewBTC = (Info.TripCount / 8) - 1;
+    BasicBlock *LoopBlk = CurLoop->getLoopLatch();
+    BranchInst *BrInst = cast<BranchInst>(LoopBlk->getTerminator());
+    CmpPredicate ExitPred = BrInst->getSuccessor(0) == LoopBlk
+                                ? ICmpInst::Predicate::ICMP_NE
+                                : ICmpInst::Predicate::ICMP_EQ;
+    Instruction *ExitCond = CurLoop->getLatchCmpInst();
+    IRBuilder<> Builder(ExitCond);
+    Value *NewExitCond = Builder.CreateICmp(
+        ExitPred, IV, ConstantInt::get(IVTy, NewBTC), "exit.cond");
+    ExitCond->replaceAllUsesWith(NewExitCond);
+    deleteDeadInstruction(ExitCond);
+  }
+
+  // Finally, fill the loop with the Sarwate-table-lookup logic, and replace all
+  // uses of ComputedValue.
+  //
+  // Little-endian:
+  //   crc = (crc >> 8) ^ tbl[data[iv] ^ (crc & 0xFF)]
+  // Big-Endian:
+  //   crc = (crc << 8) ^ tbl[data[iv] ^ (crc >> (crc.bw - 8))]
+  {
+    // Compute the top 8 bits of Op.
----------------
pfusik wrote:

Update this comment.

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


More information about the llvm-commits mailing list