Enhance SROA to "promote to scalar" allocas which are
authorChris Lattner <sabre@nondot.org>
Sun, 8 Mar 2009 04:04:21 +0000 (04:04 +0000)
committerChris Lattner <sabre@nondot.org>
Sun, 8 Mar 2009 04:04:21 +0000 (04:04 +0000)
memcpy/memmove'd into or out of.  This fixes a serious
perf issue that Nate ran into.

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

lib/Transforms/Scalar/ScalarReplAggregates.cpp
test/Transforms/ScalarRepl/2008-06-22-LargeArray.ll
test/Transforms/ScalarRepl/vector_memcpy.ll [new file with mode: 0644]

index 644625f56a0bf555581899d126432b98c275d9bd..98d5a027013fe940caa14cf11bbb527ee7d660cb 100644 (file)
@@ -1356,6 +1356,16 @@ bool SROA::CanConvertToScalar(Value *V, bool &IsNotTrivial, const Type *&VecTy,
         continue;
       }
     }
+
+    // If this is a memcpy or memmove into or out of the whole allocation, we
+    // can handle it like a load or store of the scalar type.
+    if (MemTransferInst *MTI = dyn_cast<MemTransferInst>(User)) {
+      if (ConstantInt *Len = dyn_cast<ConstantInt>(MTI->getLength()))
+        if (Len->getZExtValue() == AllocaSize && Offset == 0) {
+          IsNotTrivial = true;
+          continue;
+        }
+    }
     
     // Ignore dbg intrinsic.
     if (isa<DbgInfoIntrinsic>(User))
@@ -1440,6 +1450,44 @@ void SROA::ConvertUsesToScalar(Value *Ptr, AllocaInst *NewAI, uint64_t Offset) {
       MSI->eraseFromParent();
       continue;
     }
+
+    // If this is a memcpy or memmove into or out of the whole allocation, we
+    // can handle it like a load or store of the scalar type.
+    if (MemTransferInst *MTI = dyn_cast<MemTransferInst>(User)) {
+      assert(Offset == 0 && "must be store to start of alloca");
+      
+      // If the source and destination are both to the same alloca, then this is
+      // a noop copy-to-self, just delete it.  Otherwise, emit a load and store
+      // as appropriate.
+      AllocaInst *OrigAI = cast<AllocaInst>(Ptr->getUnderlyingObject());
+      
+      if (MTI->getSource()->getUnderlyingObject() != OrigAI) {
+        // Dest must be OrigAI, change this to be a load from the original
+        // pointer (bitcasted), then a store to our new alloca.
+        assert(MTI->getRawDest() == Ptr && "Neither use is of pointer?");
+        Value *SrcPtr = MTI->getSource();
+        SrcPtr = Builder.CreateBitCast(SrcPtr, NewAI->getType());
+        
+        LoadInst *SrcVal = Builder.CreateLoad(SrcPtr, "srcval");
+        SrcVal->setAlignment(MTI->getAlignment());
+        Builder.CreateStore(SrcVal, NewAI);
+      } else if (MTI->getDest()->getUnderlyingObject() != OrigAI) {
+        // Src must be OrigAI, change this to be a load from NewAI then a store
+        // through the original dest pointer (bitcasted).
+        assert(MTI->getRawSource() == Ptr && "Neither use is of pointer?");
+        LoadInst *SrcVal = Builder.CreateLoad(NewAI, "srcval");
+
+        Value *DstPtr = Builder.CreateBitCast(MTI->getDest(), NewAI->getType());
+        StoreInst *NewStore = Builder.CreateStore(SrcVal, DstPtr);
+        NewStore->setAlignment(MTI->getAlignment());
+      } else {
+        // Noop transfer. Src == Dst
+      }
+          
+
+      MTI->eraseFromParent();
+      continue;
+    }
     
     // If user is a dbg info intrinsic then it is safe to remove it.
     if (isa<DbgInfoIntrinsic>(User)) {
index e90dc024d7a1491f807b89ee9bc6556b1e9c8da0..8fbbb6749a9c001d1d8ddf546a02dcd222ff2cbf 100644 (file)
@@ -6,12 +6,11 @@ target triple = "i386-apple-darwin8"
 
 define void @memtest1(i8* %dst, i8* %src) nounwind  {
 entry:
-       %temp = alloca [100 x i8]               ; <[100 x i8]*> [#uses=2]
-       %"alloca point" = bitcast i32 0 to i32          ; <i32> [#uses=0]
-       %temp1 = bitcast [100 x i8]* %temp to i8*               ; <i8*> [#uses=1]
-       call void @llvm.memcpy.i32( i8* %temp1, i8* %src, i32 100, i32 1 )
-       %temp3 = bitcast [100 x i8]* %temp to i8*               ; <i8*> [#uses=1]
-       call void @llvm.memcpy.i32( i8* %dst, i8* %temp3, i32 100, i32 1 )
+       %temp = alloca [200 x i8]               ; <[100 x i8]*> [#uses=2]
+       %temp1 = bitcast [200 x i8]* %temp to i8*               ; <i8*> [#uses=1]
+       call void @llvm.memcpy.i32( i8* %temp1, i8* %src, i32 200, i32 1 )
+       %temp3 = bitcast [200 x i8]* %temp to i8*               ; <i8*> [#uses=1]
+       call void @llvm.memcpy.i32( i8* %dst, i8* %temp3, i32 200, i32 1 )
        ret void
 }
 
diff --git a/test/Transforms/ScalarRepl/vector_memcpy.ll b/test/Transforms/ScalarRepl/vector_memcpy.ll
new file mode 100644 (file)
index 0000000..dc947b0
--- /dev/null
@@ -0,0 +1,15 @@
+; RUN: llvm-as < %s | opt -scalarrepl | llvm-dis | grep {ret <16 x float> %A}
+define <16 x float> @foo(<16 x float> %A) nounwind {
+       %tmp = alloca <16 x float>, align 16
+       %tmp2 = alloca <16 x float>, align 16
+       store <16 x float> %A, <16 x float>* %tmp
+       %s = bitcast <16 x float>* %tmp to i8*
+       %s2 = bitcast <16 x float>* %tmp2 to i8*
+       call void @llvm.memcpy.i64(i8* %s2, i8* %s, i64 64, i32 16)
+       
+       %R = load <16 x float>* %tmp2
+       ret <16 x float> %R
+}
+
+declare void @llvm.memcpy.i64(i8* nocapture, i8* nocapture, i64, i32) nounwind
+