Fix an assertion in MemCpyOpt pass.
authorShuxin Yang <shuxin.llvm@gmail.com>
Fri, 7 Jun 2013 22:45:21 +0000 (22:45 +0000)
committerShuxin Yang <shuxin.llvm@gmail.com>
Fri, 7 Jun 2013 22:45:21 +0000 (22:45 +0000)
  The MemCpyOpt pass is capable of optimizing:
      callee(&S); copy N bytes from S to D.
    into:
      callee(&D);
subject to some legality constraints.

  Assertion is triggered when the compiler tries to evalute "sizeof(typeof(D))",
while D is an opaque-typed, 'sret' formal argument of function being compiled.
i.e. the signature of the func being compiled is something like this:
  T caller(...,%opaque* noalias nocapture sret %D, ...)

  The fix is that when come across such situation, instead of calling some
utility functions to get the size of D's type (which will crash), we simply
assume D has at least N bytes as implified by the copy-instruction.

rdar://14073661

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

lib/Transforms/Scalar/MemCpyOptimizer.cpp
test/Transforms/MemCpyOpt/memcpy.ll

index be0f0e8a25f6e262a6ba0ddda84eafdd5ef84038..8600c9ebf7931dcfb75bb9ad7f58000da9396543 100644 (file)
@@ -626,8 +626,10 @@ bool MemCpyOpt::performCallSlotOptzn(Instruction *cpy,
       return false;
 
     Type *StructTy = cast<PointerType>(A->getType())->getElementType();
-    uint64_t destSize = TD->getTypeAllocSize(StructTy);
-
+    // If StructTy is an opaque type, it should have at least <cpyLen> bytes,
+    // as implified by the copy-instruction.
+    uint64_t destSize = StructTy->isSized() ?
+                        TD->getTypeAllocSize(StructTy) : cpyLen;
     if (destSize < srcSize)
       return false;
   } else {
index 582a57b5d39c14a4a62a09c40ffde351f44527c1..fa768712ec937c2ce9475941a22b946f19db30f2 100644 (file)
@@ -168,6 +168,45 @@ entry:
   ret void
 }
 
+; rdar://14073661.
+; Test10 triggered assertion when the compiler try to get the size of the
+; opaque type of *x, where the x is the formal argument with attribute 'sret'.
+
+%opaque = type opaque
+declare void @foo(i32* noalias nocapture)
+
+define void @test10(%opaque* noalias nocapture sret %x, i32 %y) {
+  %a = alloca i32, align 4
+  store i32 %y, i32* %a
+  call void @foo(i32* noalias nocapture %a)
+  %c = load i32* %a
+  %d = bitcast %opaque* %x to i32*
+  store i32 %c, i32* %d
+  ret void
+}
+
+; Test11 is similar to test10 except that the instruction "store i32 %y, i32* %a"
+; before the call-site is deleted. MemCopyOpt is able to optimize this snippet into
+;
+;  %x1 = bitcast %opaque* %x to i32*
+;  call void @foo(i32* noalias nocapture %x1)
+;  ret void
+; 
+
+define void @test11(%opaque* noalias nocapture sret %x, i32 %y) {
+; CHECK: test11
+; CHECK: %x1 = bitcast %opaque* %x to i32*
+; CHECK: call void @foo(i32* noalias nocapture %x1)
+; CHECK: ret void
+
+  %a = alloca i32, align 4
+  call void @foo(i32* noalias nocapture %a)
+  %c = load i32* %a
+  %d = bitcast %opaque* %x to i32*
+  store i32 %c, i32* %d
+  ret void
+}
+
 declare void @f1(%struct.big* sret)
 declare void @f2(%struct.big*)