@@ -68,6 +68,7 @@ static cl::opt<bool> EnableMemCpyOptWithoutLibcalls(
68
68
cl::desc (" Enable memcpyopt even when libcalls are disabled" ));
69
69
70
70
STATISTIC (NumMemCpyInstr, " Number of memcpy instructions deleted" );
71
+ STATISTIC (NumMemMoveInstr, " Number of memmove instructions deleted" );
71
72
STATISTIC (NumMemSetInfer, " Number of memsets inferred" );
72
73
STATISTIC (NumMoveToCpy, " Number of memmoves converted to memcpy" );
73
74
STATISTIC (NumCpyToSet, " Number of memcpys converted to memset" );
@@ -1841,12 +1842,75 @@ bool MemCpyOptPass::processMemCpy(MemCpyInst *M, BasicBlock::iterator &BBI) {
1841
1842
return false ;
1842
1843
}
1843
1844
1845
+ // / Memmove calls with overlapping src/dest buffers that come after a memset may
1846
+ // / be removed.
1847
+ bool MemCpyOptPass::isMemMoveMemSetDependency (MemMoveInst *M) {
1848
+ const auto &DL = M->getDataLayout ();
1849
+ MemoryUseOrDef *MemMoveAccess = MSSA->getMemoryAccess (M);
1850
+ if (!MemMoveAccess)
1851
+ return false ;
1852
+
1853
+ // The memmove is of form memmove(x, x + A, B).
1854
+ MemoryLocation SourceLoc = MemoryLocation::getForSource (M);
1855
+ auto *MemMoveSourceOp = M->getSource ();
1856
+ auto *Source = dyn_cast<GEPOperator>(MemMoveSourceOp);
1857
+ if (!Source)
1858
+ return false ;
1859
+
1860
+ APInt Offset (DL.getIndexTypeSizeInBits (Source->getType ()), 0 );
1861
+ LocationSize MemMoveLocSize = SourceLoc.Size ;
1862
+ if (Source->getPointerOperand () != M->getDest () ||
1863
+ !MemMoveLocSize.hasValue () ||
1864
+ !Source->accumulateConstantOffset (DL, Offset) || Offset.isNegative ()) {
1865
+ return false ;
1866
+ }
1867
+
1868
+ uint64_t MemMoveSize = MemMoveLocSize.getValue ();
1869
+ LocationSize TotalSize =
1870
+ LocationSize::precise (Offset.getZExtValue () + MemMoveSize);
1871
+ MemoryLocation CombinedLoc (M->getDest (), TotalSize);
1872
+
1873
+ // The first dominating clobbering MemoryAccess for the combined location
1874
+ // needs to be a memset.
1875
+ BatchAAResults BAA (*AA);
1876
+ MemoryAccess *FirstDef = MemMoveAccess->getDefiningAccess ();
1877
+ auto *DestClobber = dyn_cast<MemoryDef>(
1878
+ MSSA->getWalker ()->getClobberingMemoryAccess (FirstDef, CombinedLoc, BAA));
1879
+ if (!DestClobber)
1880
+ return false ;
1881
+
1882
+ auto *MS = dyn_cast_or_null<MemSetInst>(DestClobber->getMemoryInst ());
1883
+ if (!MS)
1884
+ return false ;
1885
+
1886
+ // Memset length must be sufficiently large.
1887
+ auto *MemSetLength = dyn_cast<ConstantInt>(MS->getLength ());
1888
+ if (!MemSetLength || MemSetLength->getZExtValue () < MemMoveSize)
1889
+ return false ;
1890
+
1891
+ // The destination buffer must have been memset'd.
1892
+ if (!BAA.isMustAlias (MS->getDest (), M->getDest ()))
1893
+ return false ;
1894
+
1895
+ return true ;
1896
+ }
1897
+
1844
1898
// / Transforms memmove calls to memcpy calls when the src/dst are guaranteed
1845
1899
// / not to alias.
1846
- bool MemCpyOptPass::processMemMove (MemMoveInst *M) {
1900
+ bool MemCpyOptPass::processMemMove (MemMoveInst *M, BasicBlock::iterator &BBI ) {
1847
1901
// See if the source could be modified by this memmove potentially.
1848
- if (isModSet (AA->getModRefInfo (M, MemoryLocation::getForSource (M))))
1902
+ if (isModSet (AA->getModRefInfo (M, MemoryLocation::getForSource (M)))) {
1903
+ // On the off-chance the memmove clobbers src with previously memset'd
1904
+ // bytes, the memmove may be redundant.
1905
+ if (!M->isVolatile () && isMemMoveMemSetDependency (M)) {
1906
+ LLVM_DEBUG (dbgs () << " Removed redundant memmove.\n " );
1907
+ ++BBI;
1908
+ eraseInstruction (M);
1909
+ ++NumMemMoveInstr;
1910
+ return true ;
1911
+ }
1849
1912
return false ;
1913
+ }
1850
1914
1851
1915
LLVM_DEBUG (dbgs () << " MemCpyOptPass: Optimizing memmove -> memcpy: " << *M
1852
1916
<< " \n " );
@@ -2064,7 +2128,7 @@ bool MemCpyOptPass::iterateOnFunction(Function &F) {
2064
2128
else if (auto *M = dyn_cast<MemCpyInst>(I))
2065
2129
RepeatInstruction = processMemCpy (M, BI);
2066
2130
else if (auto *M = dyn_cast<MemMoveInst>(I))
2067
- RepeatInstruction = processMemMove (M);
2131
+ RepeatInstruction = processMemMove (M, BI );
2068
2132
else if (auto *CB = dyn_cast<CallBase>(I)) {
2069
2133
for (unsigned i = 0 , e = CB->arg_size (); i != e; ++i) {
2070
2134
if (CB->isByValArgument (i))
0 commit comments