[llvm] [MemCpyOpt] Clear writeonly from dest argument after call slot optimization (PR #95179)

via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 11 16:00:04 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: Arthur Eubanks (aeubanks)

<details>
<summary>Changes</summary>

After call slot optimization, the function may read from the parameter even if it was previously writeonly (due to the only use of it being a memcpy to it). This can cause miscompiles, as seen in #<!-- -->95152.

This is essentially intersecting the implicit alloca attributes with the argument attributes.

No need to worry about readnone/readonly since the dest already has a memcpy to it, so it shouldn't be marked readnone/readonly.

Fixes #<!-- -->95152

---
Full diff: https://github.com/llvm/llvm-project/pull/95179.diff


2 Files Affected:

- (modified) llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp (+6) 
- (added) llvm/test/Transforms/MemCpyOpt/callslot-writeonly.ll (+19) 


``````````diff
diff --git a/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp b/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp
index 8fe3780bcf1b3..1cb37e5c7bc02 100644
--- a/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp
+++ b/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp
@@ -1115,6 +1115,12 @@ bool MemCpyOptPass::performCallSlotOptzn(Instruction *cpyLoad,
   if (cpyLoad != cpyStore)
     combineAAMetadata(C, cpyStore);
 
+  // Clear writeonly from the dest if it's an argument because we may now read
+  // from it in the call.
+  if (auto *A = dyn_cast<Argument>(cpyDest))
+    if (A->hasAttribute(Attribute::WriteOnly))
+      A->removeAttr(Attribute::WriteOnly);
+
   ++NumCallSlot;
   return true;
 }
diff --git a/llvm/test/Transforms/MemCpyOpt/callslot-writeonly.ll b/llvm/test/Transforms/MemCpyOpt/callslot-writeonly.ll
new file mode 100644
index 0000000000000..c336ccf8984f0
--- /dev/null
+++ b/llvm/test/Transforms/MemCpyOpt/callslot-writeonly.ll
@@ -0,0 +1,19 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -S -passes=memcpyopt < %s | FileCheck %s
+
+; Check that we clear writeonly from the parameter when performing call slot optimization.
+
+define void @writeonly_param(ptr noalias writable writeonly dereferenceable(8) %dst) {
+; CHECK-LABEL: define void @writeonly_param(
+; CHECK-SAME: ptr noalias writable dereferenceable(8) [[DST:%.*]]) {
+; CHECK-NEXT:    [[SRC:%.*]] = alloca i64, align 8
+; CHECK-NEXT:    call void @accept_ptr(ptr nocapture [[DST]]) #[[ATTR1:[0-9]+]]
+; CHECK-NEXT:    ret void
+;
+  %src = alloca i64, align 8
+  call void @accept_ptr(ptr nocapture %src) nounwind
+  call void @llvm.memcpy.p0.p0.i64(ptr align 8 %dst, ptr %src, i64 8, i1 false)
+  ret void
+}
+
+declare void @accept_ptr(ptr)

``````````

</details>


https://github.com/llvm/llvm-project/pull/95179


More information about the llvm-commits mailing list