diff --git a/compiler-rt/test/asan/TestCases/printf-5.c b/compiler-rt/test/asan/TestCases/printf-5.c --- a/compiler-rt/test/asan/TestCases/printf-5.c +++ b/compiler-rt/test/asan/TestCases/printf-5.c @@ -14,8 +14,7 @@ volatile int x = 12; volatile float f = 1.239; volatile char s[] = "34"; - volatile char fmt[2]; - memcpy((char *)fmt, "%c %d %f %s\n", sizeof(fmt)); + volatile char fmt[2] = "%c"; printf((char *)fmt, c, x, f, s); return 0; // Check that format string is sanitized. diff --git a/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp b/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp @@ -39,8 +39,8 @@ /// the alloca, and if the source pointer is a pointer to a constant global, we /// can optimize this. static bool -isOnlyCopiedFromConstantMemory(AAResults *AA, - Value *V, MemTransferInst *&TheCopy, +isOnlyCopiedFromConstantMemory(AAResults *AA, AllocaInst *V, + MemTransferInst *&TheCopy, SmallVectorImpl &ToDelete) { // We track lifetime intrinsics as we encounter them. If we decide to go // ahead and replace the value with the global, this lets the caller quickly @@ -85,11 +85,12 @@ if (IsArgOperand && Call->isInAllocaArgument(DataOpNo)) return false; - // If this is a readonly/readnone call site, then we know it is just a - // load (but one that potentially returns the value itself), so we can + // If this call site doesn't modify the memory, then we know it is just + // a load (but one that potentially returns the value itself), so we can // ignore it if we know that the value isn't captured. - if (Call->onlyReadsMemory() && - (Call->use_empty() || Call->doesNotCapture(DataOpNo))) + bool NoCapture = Call->doesNotCapture(DataOpNo); + if ((Call->onlyReadsMemory() && (Call->use_empty() || NoCapture)) || + (Call->onlyReadsMemory(DataOpNo) && NoCapture)) continue; // If this is being passed as a byval argument, the caller is making a diff --git a/llvm/test/Transforms/InstCombine/memcpy-from-global.ll b/llvm/test/Transforms/InstCombine/memcpy-from-global.ll --- a/llvm/test/Transforms/InstCombine/memcpy-from-global.ll +++ b/llvm/test/Transforms/InstCombine/memcpy-from-global.ll @@ -338,4 +338,50 @@ ret float %r } +; Test that we can elide a memcpy when copying a constant value onto the stack +; and then forwarding it by readonly nocapture reference. +define void @test12() { +; CHECK-LABEL: @test12( +; CHECK-NEXT: call void @bar(ptr nocapture nonnull readonly @H) +; CHECK-NEXT: ret void +; + %A = alloca %U, align 16 + call void @llvm.memcpy.p0.p0.i64(ptr align 4 %A, ptr align 4 @H, i64 20, i1 false) + call void @bar(ptr nocapture readonly %A) + ret void +} + +; Test that we don't elide the memcpy when copying a constant value onto the +; stack and then forwarding it by readonly, but capturing, reference. +define void @test13() { +; CHECK-LABEL: @test13( +; CHECK-NEXT: [[A:%.*]] = alloca [[U:%.*]], align 16 +; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 16 dereferenceable(20) [[A]], ptr noundef nonnull align 16 dereferenceable(20) @H, i64 20, i1 false) +; CHECK-NEXT: call void @bar(ptr nonnull readonly [[A]]) +; CHECK-NEXT: ret void +; + %A = alloca %U, align 16 + call void @llvm.memcpy.p0.p0.i64(ptr align 4 %A, ptr align 4 @H, i64 20, i1 false) + call void @bar(ptr readonly %A) + ret void +} + +; Test that we don't elide the memcpy when copying a constant value onto the +; stack and then forwarding it by read-write, nocapture reference, even if it's +; also forwarded by readonly nocapture reference to the same function. +define void @test14() { +; CHECK-LABEL: @test14( +; CHECK-NEXT: [[A:%.*]] = alloca [[U:%.*]], align 16 +; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 16 dereferenceable(20) [[A]], ptr noundef nonnull align 16 dereferenceable(20) @H, i64 20, i1 false) +; CHECK-NEXT: call void @two_params(ptr nocapture nonnull readonly [[A]], ptr nocapture nonnull [[A]]) +; CHECK-NEXT: ret void +; + %A = alloca %U, align 16 + call void @llvm.memcpy.p0.p0.i64(ptr align 4 %A, ptr align 4 @H, i64 20, i1 false) + call void @two_params(ptr nocapture readonly %A, ptr nocapture %A) + ret void +} + +declare void @two_params(ptr nocapture readonly, ptr nocapture) + attributes #0 = { null_pointer_is_valid }