[llvm] [Transforms] Recognize memcmp-like loops in LoopIdiomRecognize (PR #181562)
Sayan Sivakumaran via llvm-commits
llvm-commits at lists.llvm.org
Sun May 31 18:41:24 PDT 2026
================
@@ -3577,3 +3588,255 @@ bool LoopIdiomRecognize::recognizeShiftUntilZero() {
++NumShiftUntilZero;
return MadeChange;
}
+
+namespace {
+class MemcmpVerifier {
+public:
+ explicit MemcmpVerifier(Loop *CurLoop, ScalarEvolution *SE, DominatorTree *DT,
+ AssumptionCache *AC, const DataLayout *DL)
+ : CurLoop(CurLoop), SE(SE), DT(DT), AC(AC), DL(DL) {}
+
+ enum class MemcmpCandidateResult {
+ RejectNotSimple,
+ RejectLoadingNonInteger,
+ RejectLoadingIntegersWithPadding,
+ RejectUnexpectedSCEV,
+ RejectPossibleOutOfBounds,
+ RejectUnexpectedAddressSpace,
+ Accept
+ };
+
+ MemcmpCandidateResult isLoadMemcmpCandidate(LoadInst *LI,
+ const SCEVUnknown *&Base,
+ const APInt *&Step) {
+ if (!LI->isSimple())
+ return MemcmpCandidateResult::RejectNotSimple;
+
+ Value *LoadPointer = LI->getPointerOperand();
+ if (LoadPointer->getType()->getPointerAddressSpace() != 0)
+ return MemcmpCandidateResult::RejectUnexpectedAddressSpace;
+
+ // Comparisons of floats can't be transformed. For example, the bits of
+ // two NaN values might be equivalent, but NaN is never equal to itself.
+ // This means `memcmp` would be a behavior change from float equality.
+ IntegerType *LoadType = dyn_cast<IntegerType>(LI->getType());
+ if (!LoadType)
+ return MemcmpCandidateResult::RejectLoadingNonInteger;
+
+ // There should be no padding between consecutive members of the integer
+ // array, as `memcmp` could give a different answer from integer equality.
+ if (DL->getTypeAllocSizeInBits(LoadType) != DL->getTypeSizeInBits(LoadType))
+ return MemcmpCandidateResult::RejectLoadingIntegersWithPadding;
----------------
sivakusayan wrote:
Okay, you're right that we can trivially transform arrays of pointers as well. What might be more complicated is transforming comparisons of arrays of aggregates, as it creates a [very different type of pattern](https://godbolt.org/z/Tr1ovMMva) than what I was looking for.
I still think it would be reasonable to implement, but I think would require a bit more code. I believe we would need to see how large the stride is between loop iterations, and then check that all of the comparisons "cover" the length of the stride. It might be better to implement the simpler, more restrictive transform first, just to keep this PR smaller.
I'll try compiling some real codebases with the simpler transform to see if it would still be useful for now.
https://github.com/llvm/llvm-project/pull/181562
More information about the llvm-commits
mailing list