Recommitting r275284: add support to inline __builtin_mempcpy

Patch by Sunita Marathe

Third try, now following fixes to MSan to handle mempcy in such a way that this commit won't break the MSan buildbots. (Thanks, Evegenii!)



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@277189 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Andrew Kaylor 2016-07-29 18:23:18 +00:00
parent bbdb447778
commit 2f75f99d2f
9 changed files with 88 additions and 1 deletions

View 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")

View File

@ -252,7 +252,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;

View File

@ -644,6 +644,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() &&

View File

@ -6043,6 +6043,49 @@ 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) {
// Verify argument count: void *mempcpy(void *, const void *, size_t)
if (I.getNumArgOperands() != 3)
return false;
SDValue Dst = getValue(I.getArgOperand(0));
SDValue Src = getValue(I.getArgOperand(1));
SDValue Size = getValue(I.getArgOperand(2));
unsigned DstAlign = DAG.InferPtrAlignment(Dst);
unsigned SrcAlign = DAG.InferPtrAlignment(Src);
unsigned Align = std::min(DstAlign, SrcAlign);
if (Align == 0) // Alignment of one or both could not be inferred.
Align = 1; // 0 and 1 both specify no alignment, but 0 is reserved.
bool isVol = false;
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);
// Check if Size needs to be truncated or extended.
Size = DAG.getSExtOrTrunc(Size, sdl, Dst.getValueType());
// 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.
@ -6333,6 +6376,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;

View 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);

View 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);

View File

@ -0,0 +1,28 @@
; RUN: llc < %s -mtriple=x86_64-unknown-linux -O2 | FileCheck %s
; RUN: llc < %s -mtriple=i686-unknown-linux -O2 | FileCheck %s
; 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.
@G = common global i8* null, align 8
; CHECK-LABEL: RET_MEMPCPY:
; CHECK: mov{{.*}} [[REG:%[er][a-z0-9]+]], {{.*}}G
; CHECK: call{{.*}} {{.*}}memcpy
; CHECK: mov{{.*}} [[REG]], %{{[er]}}ax
;
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)

View 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)

View 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(...)