[llvm] [LoopIdiom] Use costing to determine CRC strategy (PR #211040)
Piotr Fusik via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 23 07:58:09 PDT 2026
================
@@ -1589,43 +1603,110 @@ bool LoopIdiomRecognize::optimizeCRCLoop(const PolynomialInfo &Info) {
if (TT.getArch() == Triple::hexagon)
return false;
- // The force-crc-clmul flag should cause the clmul optimization to run
- // unconditionally.
- if (ForceCRCClmul) {
+ // The Sarwate lookup table optimization requires a byte-multiple trip count,
+ // and should not be applied under any circumstances if optimizing for size.
+ bool TableStrategyPossible =
+ Info.TripCount % 8 == 0 && !ApplyCodeSizeHeuristics;
+
+ switch (CRCStrategy) {
+ default:
+ break;
+ case CRCStrategyKind::Table: {
+ if (TableStrategyPossible) {
+ optimizeCRCLoopUsingTableLookup(Info);
+ return true;
+ }
+ return false;
+ }
+ case CRCStrategyKind::Clmul:
optimizeCRCLoopUsingClmul(Info);
return true;
}
- // FIXME: Once intrinsic cost modeling is more reliable for clmul, that should
- // be used to determine which optimization to use. Until then, only apply the
- // clmul optimization when optimizing for size, since a lookup table is not
- // viable in that case.
- if (!ApplyCodeSizeHeuristics && Info.TripCount % 8 == 0) {
- optimizeCRCLoopUsingTableLookup(Info);
- return true;
+ // When using the auto strategy, bail if we are optimizing for size since
+ // there's usually not a clear size benefit.
+ // TODO: The clmul optimization is around the same size in many cases, so it
+ // could be worth it to take advantage of that fact, especially if it would be
+ // much faster than the original loop.
+ if (ApplyCodeSizeHeuristics)
+ return false;
+
+ LLVMContext &Ctx = Info.LHS->getContext();
+ Type *CRCTy = Info.LHS->getType();
+ unsigned CRCBW = CRCTy->getIntegerBitWidth();
+
+ // CRC computation is mostly serial, so latency works best for comparison.
+ TargetTransformInfo::TargetCostKind CostKind =
+ TargetTransformInfo::TCK_Latency;
+
+ LLVM_DEBUG(dbgs() << DEBUG_TYPE " CRC: BW=" << CRCBW
+ << " TC=" << Info.TripCount);
+
+ InstructionCost XorCost =
+ TTI->getArithmeticInstrCost(Instruction::Xor, CRCTy, CostKind);
+ InstructionCost ShiftCost =
+ TTI->getArithmeticInstrCost(Instruction::LShr, CRCTy, CostKind);
+ InstructionCost AndCost =
+ TTI->getArithmeticInstrCost(Instruction::And, CRCTy, CostKind);
+ InstructionCost SelectCost =
+ TTI->getCmpSelInstrCost(Instruction::Select, CRCTy, Type::getInt1Ty(Ctx),
+ CmpInst::BAD_ICMP_PREDICATE, CostKind);
+ auto ClmulCost = [&](unsigned BW) {
+ auto *Ty = IntegerType::get(Ctx, BW);
+ IntrinsicCostAttributes Attrs(Intrinsic::clmul, Ty, {Ty, Ty});
+ return TTI->getIntrinsicInstrCost(Attrs, CostKind);
+ };
+
+ // Determine the cost of the alternative approach to clmul.
+ InstructionCost OldCost;
+ if (TableStrategyPossible) {
+ // If the lookup table strategy is possible, it will be faster than the
+ // original loop, so compute the cost of that strategy.
+ InstructionCost CostPerTrip =
+ TTI->getMemoryOpCost(Instruction::Load, CRCTy,
+ DL->getABITypeAlign(CRCTy),
+ DL->getDefaultGlobalsAddressSpace(), CostKind) +
+ XorCost + 2 * ShiftCost;
+
+ // The trip count will be reduced by a factor of 8.
+ OldCost = CostPerTrip * (Info.TripCount / 8);
+ LLVM_DEBUG(dbgs() << " OldCost(table)=" << OldCost);
+ } else {
+ // Estimate the cost of the original loop.
+ InstructionCost CostPerTrip =
+ 2 * ShiftCost + 2 * XorCost + AndCost + SelectCost;
+
+ OldCost = CostPerTrip * Info.TripCount;
+ LLVM_DEBUG(dbgs() << " OldCost(original)=" << OldCost);
}
- // The clmul optimization should be applied if it is fast and likely to lower
- // in a way that keeps code small.
- // TODO: If clmul exists on the target but not for the required width, it
- // might be possible to split into multiple iterations of reduction.
- unsigned ClmulMuBW = Info.IsBigEndian ? 2 * Info.TripCount : Info.TripCount;
- unsigned ClmulGPBW =
- Info.LHS->getType()->getIntegerBitWidth() + Info.TripCount;
- IntegerType *WidestClmulTy =
- IntegerType::get(Info.LHS->getContext(), std::max(ClmulMuBW, ClmulGPBW));
- if (TTI->haveFastClmul(WidestClmulTy)) {
+ // Approximate the cost of the clmul optimization as two clmuls plus a decent
+ // conservative estimate of the other operations used.
+ InstructionCost NewCost = ClmulCost(2 * Info.TripCount) +
+ ClmulCost(CRCBW + Info.TripCount) + 2 * XorCost +
+ 2 * ShiftCost + AndCost;
----------------
pfusik wrote:
Hasn't #210139 eliminated the `and` ?
https://github.com/llvm/llvm-project/pull/211040
More information about the llvm-commits
mailing list