]> granicus.if.org Git - llvm/commitdiff
Fix for Bug 26903, adds support to inline __builtin_mempcpy
authorAndrew Kaylor <andrew.kaylor@intel.com>
Wed, 13 Jul 2016 17:25:11 +0000 (17:25 +0000)
committerAndrew Kaylor <andrew.kaylor@intel.com>
Wed, 13 Jul 2016 17:25:11 +0000 (17:25 +0000)
Patch by Sunita Marathe

Differential Revision: http://reviews.llvm.org/D21920

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

include/llvm/Analysis/TargetLibraryInfo.def
include/llvm/Analysis/TargetLibraryInfo.h
lib/Analysis/TargetLibraryInfo.cpp
lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h
lib/Transforms/Utils/BuildLibCalls.cpp
test/CodeGen/Generic/mempcpy_call.ll [new file with mode: 0644]
test/CodeGen/X86/mempcpy_ret_val.ll [new file with mode: 0644]
test/Transforms/InferFunctionAttrs/annotate.ll
test/Transforms/InferFunctionAttrs/no-proto.ll

index b2a593d67dcaaab12ff30981ec2e7d22a9529379..5d5e5b127e63fccd0242a286d4c6b318e57be6ce 100644 (file)
@@ -734,6 +734,9 @@ TLI_DEFINE_STRING_INTERNAL("memcpy")
 /// void *memmove(void *s1, const void *s2, size_t n);
 TLI_DEFINE_ENUM_INTERNAL(memmove)
 TLI_DEFINE_STRING_INTERNAL("memmove")
+/// void *mempcpy(void *s1, const void *s2, size_t n);
+TLI_DEFINE_ENUM_INTERNAL(mempcpy)
+TLI_DEFINE_STRING_INTERNAL("mempcpy")
 // void *memrchr(const void *s, int c, size_t n);
 TLI_DEFINE_ENUM_INTERNAL(memrchr)
 TLI_DEFINE_STRING_INTERNAL("memrchr")
index 7efa6f05970724323634972617a5ca75cfcfbe06..411dd745533413a1b81cd755a641594a9f6d9772 100644 (file)
@@ -251,7 +251,7 @@ public:
     case LibFunc::exp2:      case LibFunc::exp2f:      case LibFunc::exp2l:
     case LibFunc::memcmp:    case LibFunc::strcmp:     case LibFunc::strcpy:
     case LibFunc::stpcpy:    case LibFunc::strlen:     case LibFunc::strnlen:
-    case LibFunc::memchr:
+    case LibFunc::memchr:    case LibFunc::mempcpy:
       return true;
     }
     return false;
index 93d537ad3abb5662e18c4a51ee91e7023c5026d3..cb02faf32b9b15f97da44b159d993eadc965b728 100644 (file)
@@ -642,6 +642,7 @@ bool TargetLibraryInfoImpl::isValidProtoForLibFunc(const FunctionType &FTy,
       return false;
   // fallthrough
   case LibFunc::memcpy:
+  case LibFunc::mempcpy:
   case LibFunc::memmove:
     return (NumParams == 3 && FTy.getReturnType() == FTy.getParamType(0) &&
             FTy.getParamType(0)->isPointerTy() &&
index 27ee96dfedfa11009c354a019a30bacdd3f1d008..26c81e9768de54857ce0ff11c07ae8a5c8345122 100644 (file)
@@ -6039,6 +6039,48 @@ bool SelectionDAGBuilder::visitMemChrCall(const CallInst &I) {
   return false;
 }
 
+///
+/// visitMemPCpyCall -- lower a mempcpy call as a memcpy followed by code to
+/// to adjust the dst pointer by the size of the copied memory.
+bool SelectionDAGBuilder::visitMemPCpyCall(const CallInst &I) {
+
+  unsigned int NumOperands = I.getNumArgOperands();
+  if (NumOperands < 3 || NumOperands > 5)
+    return false;
+
+  SDValue Dst = getValue(I.getArgOperand(0));
+  SDValue Src = getValue(I.getArgOperand(1));
+  SDValue Size = getValue(I.getArgOperand(2));
+
+  unsigned Align = 0;
+  if (NumOperands >= 4)
+    Align = cast<ConstantInt>(I.getArgOperand(3))->getZExtValue();
+  if (!Align)
+    Align = 1; // @llvm.memcpy defines 0 and 1 to both mean no alignment.
+
+  bool isVol = false;
+  if (NumOperands == 5)
+    isVol = cast<ConstantInt>(I.getArgOperand(4))->getZExtValue();
+
+  SDLoc sdl = getCurSDLoc();
+  // In the mempcpy context we need to pass in a false value for isTailCall
+  // because the return pointer needs to be adjusted by the size of
+  // the copied memory.
+  SDValue MC = DAG.getMemcpy(getRoot(), sdl, Dst, Src, Size, Align, isVol,
+                             false, /*isTailCall=*/false,
+                             MachinePointerInfo(I.getArgOperand(0)),
+                             MachinePointerInfo(I.getArgOperand(1)));
+  assert(MC.getNode() != nullptr &&
+         "** memcpy should not be lowered as TailCall in mempcpy context **");
+  DAG.setRoot(MC);
+
+  // Adjust return pointer to point just past the last dst byte.
+  SDValue DstPlusSize = DAG.getNode(ISD::ADD, sdl, Dst.getValueType(),
+                                    Dst, Size);
+  setValue(&I, DstPlusSize);
+  return true;
+}
+
 /// visitStrCpyCall -- See if we can lower a strcpy or stpcpy call into an
 /// optimized form.  If so, return true and lower it, otherwise return false
 /// and it will be lowered like a normal call.
@@ -6329,6 +6371,10 @@ void SelectionDAGBuilder::visitCall(const CallInst &I) {
         if (visitMemCmpCall(I))
           return;
         break;
+      case LibFunc::mempcpy:
+        if (visitMemPCpyCall(I))
+          return;
+        break;
       case LibFunc::memchr:
         if (visitMemChrCall(I))
           return;
index b9888ae87639e4c0f45d27affde6106787fa796e..18c39d0fccbae4f6cd23983b35f2d1b630f9e376 100644 (file)
@@ -885,6 +885,7 @@ private:
   void visitPHI(const PHINode &I);
   void visitCall(const CallInst &I);
   bool visitMemCmpCall(const CallInst &I);
+  bool visitMemPCpyCall(const CallInst &I);
   bool visitMemChrCall(const CallInst &I);
   bool visitStrCpyCall(const CallInst &I, bool isStpcpy);
   bool visitStrCmpCall(const CallInst &I);
index f4260a9ff9804758b5d894ccd611347ec7a2f068..e61b04fbdd574ab0fc8b299ee11cd64a3ec80ad9 100644 (file)
@@ -250,6 +250,7 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) {
     Changed |= setDoesNotCapture(F, 2);
     return Changed;
   case LibFunc::memcpy:
+  case LibFunc::mempcpy:
   case LibFunc::memccpy:
   case LibFunc::memmove:
     Changed |= setDoesNotThrow(F);
diff --git a/test/CodeGen/Generic/mempcpy_call.ll b/test/CodeGen/Generic/mempcpy_call.ll
new file mode 100644 (file)
index 0000000..b88f201
--- /dev/null
@@ -0,0 +1,16 @@
+; RUN: llc < %s -O2 | FileCheck %s
+
+; This test just checks that mempcpy is lowered as memcpy.
+; The test to check that the return value of mempcpy is the dst pointer adjusted
+; by the copy size is done by Codegen/X86/mempcpy_ret_val.ll
+
+; CHECK-LABEL: CALL_MEMPCPY:
+; CHECK: callq memcpy
+;
+define void @CALL_MEMPCPY(i8* %DST, i8* %SRC, i64 %N) {
+entry:
+  %call = tail call i8* @mempcpy(i8* %DST, i8* %SRC, i64 %N)
+  ret void
+}
+
+declare i8* @mempcpy(i8*, i8*, i64)
diff --git a/test/CodeGen/X86/mempcpy_ret_val.ll b/test/CodeGen/X86/mempcpy_ret_val.ll
new file mode 100644 (file)
index 0000000..d914f15
--- /dev/null
@@ -0,0 +1,28 @@
+; RUN: llc < %s -O2 | FileCheck %s
+
+@G = common global i8* null, align 8
+
+; This test checks that:
+; (1)  mempcpy is lowered as memcpy, and 
+; (2)  its return value is DST+N i.e. the dst pointer adjusted by the copy size.
+; To keep the testing of (2) independent of the exact instructions used to
+; adjust the dst pointer, DST+N is explicitly computed and stored to a global
+; variable G before the mempcpy call. This instance of DST+N causes the repeat
+; DST+N done in the context of the return value of mempcpy to be redundant, and
+; the first instance to be reused as the return value. This allows the check for
+; (2) to be expressed as verifying that the MOV to store DST+N to G and
+; the MOV to copy DST+N to %rax use the same source register.
+
+; CHECK-LABEL: RET_MEMPCPY:
+; CHECK: movq [[REG:%r[a-z0-9]+]], {{.*}}G
+; CHECK: callq memcpy
+; CHECK: movq [[REG]], %rax
+;
+define i8* @RET_MEMPCPY(i8* %DST, i8* %SRC, i64 %N) {
+  %add.ptr = getelementptr inbounds i8, i8* %DST, i64 %N
+  store i8* %add.ptr, i8** @G, align 8
+  %call = tail call i8* @mempcpy(i8* %DST, i8* %SRC, i64 %N) 
+  ret i8* %call
+}
+
+declare i8* @mempcpy(i8*, i8*, i64)
index 039114d0cb985baa05ac4f3a28ac3c054d18e95a..64676bf310bd401c8cd07b5f43776c9019b90e85 100644 (file)
@@ -499,6 +499,9 @@ declare i32 @memcmp(i8*, i8*, i64)
 ; CHECK: declare i8* @memcpy(i8*, i8* nocapture readonly, i64) [[G0]]
 declare i8* @memcpy(i8*, i8*, i64)
 
+; CHECK: declare i8* @mempcpy(i8*, i8* nocapture readonly, i64) [[G0]]
+declare i8* @mempcpy(i8*, i8*, i64)
+
 ; CHECK: declare i8* @memmove(i8*, i8* nocapture readonly, i64) [[G0]]
 declare i8* @memmove(i8*, i8*, i64)
 
index 256f5c356b81a8dd3710a4b05c5850afbc9bb8a4..25a4805c367fed6a06bc6cbfeed92d32a3ac74bd 100644 (file)
@@ -480,6 +480,9 @@ declare void @memcmp(...)
 ; CHECK: declare void @memcpy(...)
 declare void @memcpy(...)
 
+; CHECK: declare void @mempcpy(...)
+declare void @mempcpy(...)
+
 ; CHECK: declare void @memmove(...)
 declare void @memmove(...)