Skip to content

Commit 2afe678

Browse files
authored
[MemCpyOpt] Allow memcpy elision for non-noalias arguments (llvm#107860)
We currently elide memcpys for readonly nocapture noalias arguments. noalias is checked to make sure that there are no other ways to write the memory, e.g. through a different argument or an escaped pointer. In addition to the current noalias check, also query alias analysis, in case it can prove that modification is not possible through other means. This fixes the problem reported in https://discourse.llvm.org/t/problem-about-memcpy-elimination/81121.
1 parent 19f604e commit 2afe678

File tree

2 files changed

+16
-10
lines changed

2 files changed

+16
-10
lines changed

llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1950,7 +1950,7 @@ bool MemCpyOptPass::processByValArgument(CallBase &CB, unsigned ArgNo) {
19501950
/// during call. Try to use memcpy source directly if all of the following
19511951
/// conditions are satisfied.
19521952
/// 1. The memcpy dst is neither modified during the call nor captured by the
1953-
/// call. (if readonly, noalias, nocapture attributes on call-site.)
1953+
/// call.
19541954
/// 2. The memcpy dst is an alloca with known alignment & size.
19551955
/// 2-1. The memcpy length == the alloca size which ensures that the new
19561956
/// pointer is dereferenceable for the required range
@@ -1961,12 +1961,22 @@ bool MemCpyOptPass::processByValArgument(CallBase &CB, unsigned ArgNo) {
19611961
/// 4. The memcpy src is not modified during the call. (ModRef check shows no
19621962
/// Mod.)
19631963
bool MemCpyOptPass::processImmutArgument(CallBase &CB, unsigned ArgNo) {
1964+
BatchAAResults BAA(*AA);
1965+
Value *ImmutArg = CB.getArgOperand(ArgNo);
1966+
19641967
// 1. Ensure passed argument is immutable during call.
1965-
if (!(CB.paramHasAttr(ArgNo, Attribute::NoAlias) &&
1966-
CB.paramHasAttr(ArgNo, Attribute::NoCapture)))
1968+
if (!CB.paramHasAttr(ArgNo, Attribute::NoCapture))
1969+
return false;
1970+
1971+
// We know that the argument is readonly at this point, but the function
1972+
// might still modify the same memory through a different pointer. Exclude
1973+
// this either via noalias, or alias analysis.
1974+
if (!CB.paramHasAttr(ArgNo, Attribute::NoAlias) &&
1975+
isModSet(
1976+
BAA.getModRefInfo(&CB, MemoryLocation::getBeforeOrAfter(ImmutArg))))
19671977
return false;
1978+
19681979
const DataLayout &DL = CB.getDataLayout();
1969-
Value *ImmutArg = CB.getArgOperand(ArgNo);
19701980

19711981
// 2. Check that arg is alloca
19721982
// TODO: Even if the arg gets back to branches, we can remove memcpy if all
@@ -1986,7 +1996,6 @@ bool MemCpyOptPass::processImmutArgument(CallBase &CB, unsigned ArgNo) {
19861996
return false;
19871997

19881998
MemCpyInst *MDep = nullptr;
1989-
BatchAAResults BAA(*AA);
19901999
MemoryAccess *Clobber = MSSA->getWalker()->getClobberingMemoryAccess(
19912000
CallAccess->getDefiningAccess(), Loc, BAA);
19922001
if (auto *MD = dyn_cast<MemoryDef>(Clobber))

llvm/test/Transforms/MemCpyOpt/memcpy.ll

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -472,9 +472,7 @@ define void @immut_param_mayalias(ptr align 4 noalias %val) {
472472
; argument doesn't matter.
473473
define void @immut_param_unescaped_alloca(ptr align 4 noalias %val) {
474474
; CHECK-LABEL: @immut_param_unescaped_alloca(
475-
; CHECK-NEXT: [[VAL1:%.*]] = alloca i8, align 4
476-
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[VAL1]], ptr align 4 [[VAL:%.*]], i64 1, i1 false)
477-
; CHECK-NEXT: call void @f(ptr nocapture readonly align 4 [[VAL1]])
475+
; CHECK-NEXT: call void @f(ptr nocapture readonly align 4 [[VAL:%.*]])
478476
; CHECK-NEXT: ret void
479477
;
480478
%val1 = alloca i8, align 4
@@ -489,8 +487,7 @@ define void @immut_param_memory_argmem_read(ptr align 4 noalias %val) {
489487
; CHECK-LABEL: @immut_param_memory_argmem_read(
490488
; CHECK-NEXT: [[VAL1:%.*]] = alloca i8, align 4
491489
; CHECK-NEXT: call void @f(ptr [[VAL1]])
492-
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[VAL1]], ptr align 4 [[VAL:%.*]], i64 1, i1 false)
493-
; CHECK-NEXT: call void @f(ptr nocapture readonly align 4 [[VAL1]]) #[[ATTR6:[0-9]+]]
490+
; CHECK-NEXT: call void @f(ptr nocapture readonly align 4 [[VAL:%.*]]) #[[ATTR6:[0-9]+]]
494491
; CHECK-NEXT: ret void
495492
;
496493
%val1 = alloca i8, align 4

0 commit comments

Comments
 (0)