Index: llvm/include/llvm/Transforms/Scalar/MemCpyOptimizer.h =================================================================== --- llvm/include/llvm/Transforms/Scalar/MemCpyOptimizer.h +++ llvm/include/llvm/Transforms/Scalar/MemCpyOptimizer.h @@ -73,6 +73,7 @@ bool performMemCpyToMemSetOptzn(MemCpyInst *MemCpy, MemSetInst *MemSet, BatchAAResults &BAA); bool processByValArgument(CallBase &CB, unsigned ArgNo); + bool processNoAliasOnlyRead(CallBase &CB, unsigned ArgNo); Instruction *tryMergingIntoMemset(Instruction *I, Value *StartPtr, Value *ByteVal); bool moveUp(StoreInst *SI, Instruction *P, const LoadInst *LI); Index: llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp =================================================================== --- llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp +++ llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp @@ -1613,6 +1613,91 @@ return true; } +/// This is called on arguments attributed with noalias and readonly/readnone +// TODO: rename as nocapture necessary +bool MemCpyOptPass::processNoAliasOnlyRead(CallBase &CB, unsigned ArgNo) { + const DataLayout &DL = CB.getCaller()->getParent()->getDataLayout(); + // Find out what feeds this byval argument. + Value *NoAliasOnlyReadArg = CB.getArgOperand(ArgNo); + Type *NoAliasOnlyReadTy = CB.getParamByValType(ArgNo); + + TypeSize NoAliasOnlyReadSize = DL.getTypeAllocSize(NoAliasOnlyReadTy); + dbgs() << "this won't be execed\n"; + MemoryLocation Loc(NoAliasOnlyReadArg, + LocationSize::precise(NoAliasOnlyReadSize)); + MemoryUseOrDef *CallAccess = MSSA->getMemoryAccess(&CB); + if (!CallAccess) + return false; + MemCpyInst *MDep = nullptr; + BatchAAResults BAA(*AA); + MemoryAccess *Clobber = MSSA->getWalker()->getClobberingMemoryAccess( + CallAccess->getDefiningAccess(), Loc, BAA); + if (auto *MD = dyn_cast(Clobber)) + MDep = dyn_cast_or_null(MD->getMemoryInst()); + + // If the byval argument isn't fed by a memcpy, ignore it. If it is fed by + // a memcpy, see if we can byval from the source of the memcpy instead of the + // result. + if (!MDep || MDep->isVolatile() || + NoAliasOnlyReadArg->stripPointerCasts() != MDep->getDest()) + return false; + + // The length of the memcpy must be larger or equal to the size of the byval. + auto *C1 = dyn_cast(MDep->getLength()); + if (!C1 || + !TypeSize::isKnownGE(TypeSize::getFixed(C1->getValue().getZExtValue()), + NoAliasOnlyReadSize)) + return false; + + // Get the alignment of the byval. If the call doesn't specify the alignment, + // then it is some target specific value that we can't know. + MaybeAlign NoAliasOnlyReadAlign = CB.getParamAlign(ArgNo); + if (!NoAliasOnlyReadAlign) + return false; + + // If it is greater than the memcpy, then we check to see if we can force the + // source of the memcpy to the alignment we need. If we fail, we bail out. + MaybeAlign MemDepAlign = MDep->getSourceAlign(); + if ((!MemDepAlign || *MemDepAlign < *NoAliasOnlyReadAlign) && + getOrEnforceKnownAlignment(MDep->getSource(), NoAliasOnlyReadAlign, DL, + &CB, AC, DT) < *NoAliasOnlyReadAlign) + return false; + dbgs() << "after alignment\n"; + + // The address space of the memcpy source must match the byval argument + if (MDep->getSource()->getType()->getPointerAddressSpace() != + NoAliasOnlyReadArg->getType()->getPointerAddressSpace()) + return false; + + // Verify that the copied-from memory doesn't change in between the memcpy and + // the byval call. + // memcpy(a <- b) + // *b = 42; + // foo(*a) + // It would be invalid to transform the second memcpy into foo(*b). + if (writtenBetween(MSSA, BAA, MemoryLocation::getForSource(MDep), + MSSA->getMemoryAccess(MDep), MSSA->getMemoryAccess(&CB))) + return false; + + Value *TmpCast = MDep->getSource(); + if (MDep->getSource()->getType() != NoAliasOnlyReadArg->getType()) { + BitCastInst *TmpBitCast = new BitCastInst( + MDep->getSource(), NoAliasOnlyReadArg->getType(), "tmpcast", &CB); + // Set the tmpcast's DebugLoc to MDep's + TmpBitCast->setDebugLoc(MDep->getDebugLoc()); + TmpCast = TmpBitCast; + } + + LLVM_DEBUG(dbgs() << "MemCpyOptPass: Forwarding memcpy to noalias readonly:\n" + << " " << *MDep << "\n" + << " " << CB << "\n"); + + // Otherwise we're good! Update the byval argument. + CB.setArgOperand(ArgNo, TmpCast); + ++NumMemCpyInstr; + return true; +} + /// Executes one iteration of MemCpyOptPass. bool MemCpyOptPass::iterateOnFunction(Function &F) { bool MadeChange = false; @@ -1641,9 +1726,16 @@ else if (auto *M = dyn_cast(I)) RepeatInstruction = processMemMove(M); else if (auto *CB = dyn_cast(I)) { - for (unsigned i = 0, e = CB->arg_size(); i != e; ++i) + for (unsigned i = 0, e = CB->arg_size(); i != e; ++i) { if (CB->isByValArgument(i)) MadeChange |= processByValArgument(*CB, i); + else if (CB->onlyReadsMemory(i)) { + if (!(CB->paramHasAttr(i, Attribute::NoAlias) && + CB->paramHasAttr(i, Attribute::NoCapture))) + continue; + MadeChange |= processNoAliasOnlyRead(*CB, i); + } + } } // Reprocess the instruction if desired.