[llvm] [memcpyopt] handle memcpy from memset in more cases (PR #140954)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Jun 2 01:27:49 PDT 2025
================
@@ -1418,51 +1437,63 @@ static bool hasUndefContents(MemorySSA *MSSA, BatchAAResults &AA, Value *V,
bool MemCpyOptPass::performMemCpyToMemSetOptzn(MemCpyInst *MemCpy,
MemSetInst *MemSet,
BatchAAResults &BAA) {
- // Make sure that memcpy(..., memset(...), ...), that is we are memsetting and
- // memcpying from the same address. Otherwise it is hard to reason about.
- if (!BAA.isMustAlias(MemSet->getRawDest(), MemCpy->getRawSource()))
- return false;
-
Value *MemSetSize = MemSet->getLength();
Value *CopySize = MemCpy->getLength();
- if (MemSetSize != CopySize) {
- // Make sure the memcpy doesn't read any more than what the memset wrote.
- // Don't worry about sizes larger than i64.
-
- // A known memset size is required.
- auto *CMemSetSize = dyn_cast<ConstantInt>(MemSetSize);
- if (!CMemSetSize)
+ int64_t MOffset = 0;
+ const DataLayout &DL = MemCpy->getModule()->getDataLayout();
+ // We can only transforms memcpy's where the dest of one is the source of the
+ // other, or they have a known offset.
+ if (MemCpy->getSource() != MemSet->getDest()) {
+ std::optional<int64_t> Offset =
+ MemCpy->getSource()->getPointerOffsetFrom(MemSet->getDest(), DL);
+ if (!Offset)
return false;
+ MOffset = *Offset;
+ }
- // A known memcpy size is also required.
+ MaybeAlign MDestAlign = MemCpy->getDestAlign();
+ int64_t MOffsetAligned = MDestAlign.valueOrOne().value() > 1 && MOffset < 0 ? -(-MOffset & ~(MDestAlign.valueOrOne().value() - 1)) : MOffset; // Compute the MOffset that keeps MDest aligned (truncate towards zero)
+ if (MOffset != 0 || MemSetSize != CopySize) {
+ // Make sure the memcpy doesn't read any more than what the memset wrote, other than undef.
+ auto *CMemSetSize = dyn_cast<ConstantInt>(MemSetSize);
auto *CCopySize = dyn_cast<ConstantInt>(CopySize);
- if (!CCopySize)
- return false;
- if (CCopySize->getZExtValue() > CMemSetSize->getZExtValue()) {
- // If the memcpy is larger than the memset, but the memory was undef prior
- // to the memset, we can just ignore the tail. Technically we're only
- // interested in the bytes from MemSetSize..CopySize here, but as we can't
- // easily represent this location, we use the full 0..CopySize range.
- MemoryLocation MemCpyLoc = MemoryLocation::getForSource(MemCpy);
- bool CanReduceSize = false;
- MemoryUseOrDef *MemSetAccess = MSSA->getMemoryAccess(MemSet);
- MemoryAccess *Clobber = MSSA->getWalker()->getClobberingMemoryAccess(
- MemSetAccess->getDefiningAccess(), MemCpyLoc, BAA);
- if (auto *MD = dyn_cast<MemoryDef>(Clobber))
- if (hasUndefContents(MSSA, BAA, MemCpy->getSource(), MD, CopySize))
- CanReduceSize = true;
-
- if (!CanReduceSize)
+ // Don't worry about sizes larger than i64.
+ if (!CMemSetSize || !CCopySize || MOffset < 0 ||
+ CCopySize->getZExtValue() + MOffset > CMemSetSize->getZExtValue()) {
+ if (!coversInputFully(MSSA, MemCpy, MemSet, BAA))
return false;
- CopySize = MemSetSize;
+
+ if (CMemSetSize && CCopySize) {
+ // If both have constant sizes and offsets, clip the memcpy to the bounds of the memset if applicable.
+ if (CCopySize->getZExtValue() + std::abs(MOffset) > CMemSetSize->getZExtValue()) {
+ if (MOffsetAligned == 0 || (MOffset < 0 && CCopySize->getZExtValue() + MOffset > CMemSetSize->getZExtValue()))
+ CopySize = MemSetSize;
+ else
+ CopySize = ConstantInt::get(CopySize->getType(), std::max((int64_t)0, (int64_t)(CMemSetSize->getZExtValue() - std::abs(MOffsetAligned))));
+ }
+ else if (MOffsetAligned < 0) {
----------------
dianqk wrote:
Can you explain what the `MOffsetAligned` variable is? Or, what are you calculating here?
https://github.com/llvm/llvm-project/pull/140954
More information about the llvm-commits
mailing list