diff options
-rw-r--r-- | llvm/include/llvm/Analysis/TargetLibraryInfo.def | 3 | ||||
-rw-r--r-- | llvm/include/llvm/Analysis/TargetLibraryInfo.h | 2 | ||||
-rw-r--r-- | llvm/lib/Analysis/TargetLibraryInfo.cpp | 1 | ||||
-rw-r--r-- | llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | 46 | ||||
-rw-r--r-- | llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h | 1 | ||||
-rw-r--r-- | llvm/lib/Transforms/Utils/BuildLibCalls.cpp | 1 | ||||
-rw-r--r-- | llvm/test/CodeGen/Generic/mempcpy_call.ll | 16 | ||||
-rw-r--r-- | llvm/test/CodeGen/X86/mempcpy_ret_val.ll | 28 | ||||
-rw-r--r-- | llvm/test/Transforms/InferFunctionAttrs/annotate.ll | 3 | ||||
-rw-r--r-- | llvm/test/Transforms/InferFunctionAttrs/no-proto.ll | 3 |
10 files changed, 103 insertions, 1 deletions
diff --git a/llvm/include/llvm/Analysis/TargetLibraryInfo.def b/llvm/include/llvm/Analysis/TargetLibraryInfo.def index b2a593d67dc..5d5e5b127e6 100644 --- a/llvm/include/llvm/Analysis/TargetLibraryInfo.def +++ b/llvm/include/llvm/Analysis/TargetLibraryInfo.def @@ -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") diff --git a/llvm/include/llvm/Analysis/TargetLibraryInfo.h b/llvm/include/llvm/Analysis/TargetLibraryInfo.h index 7efa6f05970..411dd745533 100644 --- a/llvm/include/llvm/Analysis/TargetLibraryInfo.h +++ b/llvm/include/llvm/Analysis/TargetLibraryInfo.h @@ -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; diff --git a/llvm/lib/Analysis/TargetLibraryInfo.cpp b/llvm/lib/Analysis/TargetLibraryInfo.cpp index 93d537ad3ab..cb02faf32b9 100644 --- a/llvm/lib/Analysis/TargetLibraryInfo.cpp +++ b/llvm/lib/Analysis/TargetLibraryInfo.cpp @@ -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() && diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index 27ee96dfedf..26c81e9768d 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -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; diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h index b9888ae8763..18c39d0fccb 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h @@ -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); diff --git a/llvm/lib/Transforms/Utils/BuildLibCalls.cpp b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp index f4260a9ff98..e61b04fbdd5 100644 --- a/llvm/lib/Transforms/Utils/BuildLibCalls.cpp +++ b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp @@ -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/llvm/test/CodeGen/Generic/mempcpy_call.ll b/llvm/test/CodeGen/Generic/mempcpy_call.ll new file mode 100644 index 00000000000..b88f20160af --- /dev/null +++ b/llvm/test/CodeGen/Generic/mempcpy_call.ll @@ -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/llvm/test/CodeGen/X86/mempcpy_ret_val.ll b/llvm/test/CodeGen/X86/mempcpy_ret_val.ll new file mode 100644 index 00000000000..d914f15101b --- /dev/null +++ b/llvm/test/CodeGen/X86/mempcpy_ret_val.ll @@ -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) diff --git a/llvm/test/Transforms/InferFunctionAttrs/annotate.ll b/llvm/test/Transforms/InferFunctionAttrs/annotate.ll index 039114d0cb9..64676bf310b 100644 --- a/llvm/test/Transforms/InferFunctionAttrs/annotate.ll +++ b/llvm/test/Transforms/InferFunctionAttrs/annotate.ll @@ -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) diff --git a/llvm/test/Transforms/InferFunctionAttrs/no-proto.ll b/llvm/test/Transforms/InferFunctionAttrs/no-proto.ll index 256f5c356b8..25a4805c367 100644 --- a/llvm/test/Transforms/InferFunctionAttrs/no-proto.ll +++ b/llvm/test/Transforms/InferFunctionAttrs/no-proto.ll @@ -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(...) |