Lower memcpy if it makes sense.
authorDevang Patel <dpatel@apple.com>
Thu, 11 Oct 2007 17:21:57 +0000 (17:21 +0000)
committerDevang Patel <dpatel@apple.com>
Thu, 11 Oct 2007 17:21:57 +0000 (17:21 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@42864 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Transforms/Scalar/InstructionCombining.cpp
test/Transforms/InstCombine/2007-10-10-EliminateMemCpy.ll [new file with mode: 0644]

index 2311f1eb5a3b56dea5bd17033bf25d7f92d29b47..5ff971427de09f2adb8043f0a6652e5f6b308420 100644 (file)
@@ -7669,6 +7669,52 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) {
         MI->setAlignment(ConstantInt::get(Type::Int32Ty, Align));
         Changed = true;
       }
+
+      // If MemCpyInst length is 1/2/4/8 bytes then replace memcpy with load/store
+      ConstantInt *MemOpLength = dyn_cast<ConstantInt>(CI.getOperand(3));
+      if (isa<MemCpyInst>(MI))
+        if (MemOpLength) {
+        unsigned Size = MemOpLength->getZExtValue();
+        unsigned Align = cast<ConstantInt>(CI.getOperand(4))->getZExtValue();
+        const PointerType *PTy = cast<PointerType>(CI.getOperand(1)->getType());
+        const Type *MTy = PTy->getElementType();
+        PointerType *NewPtrTy = NULL;
+        if (MTy == Type::Int8Ty) {
+          if (Size == 8)
+            NewPtrTy = PointerType::get(Type::Int64Ty);
+          else if (Size == 4)
+            NewPtrTy = PointerType::get(Type::Int32Ty);
+          else if (Size == 2)
+            NewPtrTy = PointerType::get(Type::Int16Ty);
+          else if (Size == 1)
+            NewPtrTy = PointerType::get(Type::Int8Ty);
+        } else if (MTy == Type::Int16Ty) {
+          if (Size == 4)
+            NewPtrTy = PointerType::get(Type::Int64Ty);
+          else if (Size == 2)
+            NewPtrTy = PointerType::get(Type::Int32Ty);
+          else if (Size == 1)
+            NewPtrTy = PointerType::get(Type::Int16Ty);
+        } else if (MTy == Type::Int32Ty) {
+          if (Size == 2)
+            NewPtrTy = PointerType::get(Type::Int64Ty);
+          else if (Size == 1)
+            NewPtrTy = PointerType::get(Type::Int32Ty);
+        } else if (MTy == Type::Int64Ty) {
+          if (Size == 1)
+            NewPtrTy = PointerType::get(Type::Int64Ty);
+        }
+        if (NewPtrTy)
+        {
+          Value *Src = InsertCastBefore(Instruction::BitCast, CI.getOperand(2), NewPtrTy, CI);
+          Value *Dest = InsertCastBefore(Instruction::BitCast, CI.getOperand(1), NewPtrTy, CI);
+          Value *L = new LoadInst(Src, "tmp", false, Align, &CI);
+          Value *NS = new StoreInst(L, Dest, false, Align, &CI);
+          CI.replaceAllUsesWith(NS);
+          Changed = true;
+          return EraseInstFromFunction(CI);
+        }
+      }
     } else if (isa<MemSetInst>(MI)) {
       unsigned Alignment = GetOrEnforceKnownAlignment(MI->getDest(), TD);
       if (MI->getAlignment()->getZExtValue() < Alignment) {
diff --git a/test/Transforms/InstCombine/2007-10-10-EliminateMemCpy.ll b/test/Transforms/InstCombine/2007-10-10-EliminateMemCpy.ll
new file mode 100644 (file)
index 0000000..5cc6e3b
--- /dev/null
@@ -0,0 +1,18 @@
+; RUN: llvm-as < %s | opt -instcombine | llvm-dis | not grep call
+@.str = internal constant [4 x i8] c"xyz\00"           ; <[4 x i8]*> [#uses=1]
+
+define void @foo(i8* %P) {
+entry:
+       %P_addr = alloca i8*            ; <i8**> [#uses=2]
+       %"alloca point" = bitcast i32 0 to i32          ; <i32> [#uses=0]
+       store i8* %P, i8** %P_addr
+       %tmp = load i8** %P_addr, align 4               ; <i8*> [#uses=1]
+       %tmp1 = getelementptr [4 x i8]* @.str, i32 0, i32 0             ; <i8*> [#uses=1]
+       call void @llvm.memcpy.i32( i8* %tmp, i8* %tmp1, i32 4, i32 1 )
+       br label %return
+
+return:                ; preds = %entry
+       ret void
+}
+
+declare void @llvm.memcpy.i32(i8*, i8*, i32, i32)