]> granicus.if.org Git - llvm/commitdiff
[MemCpyOpt] Fixing Incorrect Code Motion while Handling Aggregate Type Values
authorSam Elliott <selliott@lowrisc.org>
Mon, 21 Oct 2019 10:00:34 +0000 (10:00 +0000)
committerSam Elliott <selliott@lowrisc.org>
Mon, 21 Oct 2019 10:00:34 +0000 (10:00 +0000)
Summary:
When MemCpyOpt is handling aggregate type values, if an instruction (let's call it P) between the targeting load (L) and store (S) clobbers the source pointer of L, it will try to hoist S before P. This process will also hoist S's data dependency instructions.

However, the current implementation has a bug that if one of S's dependency instructions is //also// a user of P, MemCpyOpt will not prevent it from being hoisted above P and cause a use-before-define error. For example, in the newly added test file (i.e. `aggregate-type-crash.ll`), it will try to hoist both `store %my_struct %1, %my_struct* %3` and its dependent, `%3 = bitcast i8* %2 to %my_struct*`, above `%2 = call i8* @my_malloc(%my_struct* %0)`. Creating the following BB:
```
entry:
  %1 = bitcast i8* %4 to %my_struct*
  %2 = bitcast %my_struct* %1 to i8*
  %3 = bitcast %my_struct* %0 to i8*
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %2, i8* align 4 %3, i64 8, i1 false)
  %4 = call i8* @my_malloc(%my_struct* %0)
  ret void
```
Where there is a use-before-define error between `%1` and `%4`.

Update: The compiler for the Pony Programming Language [also encounter the same bug](https://github.com/ponylang/ponyc/issues/3140)

Patch by Min-Yih Hsu (myhsu)

Reviewers: eugenis, pcc, dblaikie, dneilson, t.p.northover, lattner

Reviewed By: eugenis

Subscribers: lenary, hiraditya, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D66060

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@375403 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Transforms/Scalar/MemCpyOptimizer.cpp
test/Transforms/MemCpyOpt/aggregate-type-crash.ll [new file with mode: 0644]

index 37d6d6085e4302bc0a62a2022535bca4d002a9c7..2364748efb0579a06596dc3a5e47d24f6c3c4134 100644 (file)
@@ -513,9 +513,13 @@ static bool moveUp(AliasAnalysis &AA, StoreInst *SI, Instruction *P,
 
     ToLift.push_back(C);
     for (unsigned k = 0, e = C->getNumOperands(); k != e; ++k)
-      if (auto *A = dyn_cast<Instruction>(C->getOperand(k)))
-        if (A->getParent() == SI->getParent())
+      if (auto *A = dyn_cast<Instruction>(C->getOperand(k))) {
+        if (A->getParent() == SI->getParent()) {
+          // Cannot hoist user of P above P
+          if(A == P) return false;
           Args.insert(A);
+        }
+      }
   }
 
   // We made it, we need to lift
diff --git a/test/Transforms/MemCpyOpt/aggregate-type-crash.ll b/test/Transforms/MemCpyOpt/aggregate-type-crash.ll
new file mode 100644 (file)
index 0000000..16d1077
--- /dev/null
@@ -0,0 +1,30 @@
+; RUN: opt -memcpyopt -S -o - < %s | FileCheck %s
+
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.14.0"
+
+%my_struct = type { i8, i32 }
+
+; Function Attrs: inaccessiblemem_or_argmemonly
+declare noalias i8* @my_malloc(%my_struct*) #0
+
+define void @my_func(%my_struct* %0) {
+entry:
+; CHECK: entry:
+  %1 = load %my_struct, %my_struct* %0
+  %2 = call i8* @my_malloc(%my_struct* %0)
+  %3 = bitcast i8* %2 to %my_struct*
+  store %my_struct %1, %my_struct* %3
+; CHECK-NOT: call void @llvm.memcpy.{{.*}}.{{.*}}.{{.*}}
+  ret void
+}
+
+attributes #0 = { inaccessiblemem_or_argmemonly }
+
+!llvm.module.flags = !{!0, !1, !2}
+!llvm.ident = !{!3}
+
+!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 10, i32 14]}
+!1 = !{i32 1, !"wchar_size", i32 4}
+!2 = !{i32 7, !"PIC Level", i32 2}
+!3 = !{!"Apple LLVM version 10.0.1 (clang-1001.0.46.4)"}