From 3f1fd59de3002e3d5a4eca98cd49c45755ab0110 Mon Sep 17 00:00:00 2001 From: =?utf8?q?D=C3=A1vid=20Bolvansk=C3=BD?= Date: Mon, 5 Oct 2020 22:16:59 +0200 Subject: [PATCH] [SLC] Optimize mempcpy_chk to mempcpy As reported in PR46735: void* f(void *d, const void *s, size_t l) { return __builtin___mempcpy_chk(d, s, l, __builtin_object_size(d, 0)); } This can be optimized to `return mempcpy(d, s, l);`. Reviewed By: efriedma Differential Revision: https://reviews.llvm.org/D86019 --- llvm/include/llvm/Analysis/TargetLibraryInfo.def | 3 +++ llvm/include/llvm/Transforms/Utils/BuildLibCalls.h | 4 ++++ .../llvm/Transforms/Utils/SimplifyLibCalls.h | 1 + llvm/lib/Analysis/TargetLibraryInfo.cpp | 1 + llvm/lib/Transforms/Utils/BuildLibCalls.cpp | 9 +++++++++ llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp | 15 ++++++++++++++ .../test/Transforms/InstCombine/fortify-folding.ll | 23 ++++++++++++++++++++++ 7 files changed, 56 insertions(+) diff --git a/llvm/include/llvm/Analysis/TargetLibraryInfo.def b/llvm/include/llvm/Analysis/TargetLibraryInfo.def index 36b39f4..7501d1a 100644 --- a/llvm/include/llvm/Analysis/TargetLibraryInfo.def +++ b/llvm/include/llvm/Analysis/TargetLibraryInfo.def @@ -366,6 +366,9 @@ TLI_DEFINE_STRING_INTERNAL("__memcpy_chk") /// void *__memmove_chk(void *s1, const void *s2, size_t n, size_t s1size); TLI_DEFINE_ENUM_INTERNAL(memmove_chk) TLI_DEFINE_STRING_INTERNAL("__memmove_chk") +/// void *__mempcpy_chk(void *s1, const void *s2, size_t n, size_t s1size); +TLI_DEFINE_ENUM_INTERNAL(mempcpy_chk) +TLI_DEFINE_STRING_INTERNAL("__mempcpy_chk") /// void *__memset_chk(void *s, char v, size_t n, size_t s1size); TLI_DEFINE_ENUM_INTERNAL(memset_chk) TLI_DEFINE_STRING_INTERNAL("__memset_chk") diff --git a/llvm/include/llvm/Transforms/Utils/BuildLibCalls.h b/llvm/include/llvm/Transforms/Utils/BuildLibCalls.h index 90517e8..e7d4193 100644 --- a/llvm/include/llvm/Transforms/Utils/BuildLibCalls.h +++ b/llvm/include/llvm/Transforms/Utils/BuildLibCalls.h @@ -96,6 +96,10 @@ namespace llvm { IRBuilderBase &B, const DataLayout &DL, const TargetLibraryInfo *TLI); + /// Emit a call to the mempcpy function. + Value *emitMemPCpy(Value *Dst, Value *Src, Value *Len, IRBuilderBase &B, + const DataLayout &DL, const TargetLibraryInfo *TLI); + /// Emit a call to the memchr function. This assumes that Ptr is a pointer, /// Val is an i32 value, and Len is an 'intptr_t' value. Value *emitMemChr(Value *Ptr, Value *Val, Value *Len, IRBuilderBase &B, diff --git a/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h b/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h index 2819a34..8703434 100644 --- a/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h +++ b/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h @@ -59,6 +59,7 @@ private: Value *optimizeStrpCpyChk(CallInst *CI, IRBuilderBase &B, LibFunc Func); Value *optimizeStrpNCpyChk(CallInst *CI, IRBuilderBase &B, LibFunc Func); Value *optimizeStrLenChk(CallInst *CI, IRBuilderBase &B); + Value *optimizeMemPCpyChk(CallInst *CI, IRBuilderBase &B); Value *optimizeMemCCpyChk(CallInst *CI, IRBuilderBase &B); Value *optimizeSNPrintfChk(CallInst *CI, IRBuilderBase &B); Value *optimizeSPrintfChk(CallInst *CI,IRBuilderBase &B); diff --git a/llvm/lib/Analysis/TargetLibraryInfo.cpp b/llvm/lib/Analysis/TargetLibraryInfo.cpp index e629d04..d9b263b 100644 --- a/llvm/lib/Analysis/TargetLibraryInfo.cpp +++ b/llvm/lib/Analysis/TargetLibraryInfo.cpp @@ -847,6 +847,7 @@ bool TargetLibraryInfoImpl::isValidProtoForLibFunc(const FunctionType &FTy, return (NumParams >= 2 && FTy.getParamType(1)->isPointerTy()); case LibFunc_memcpy_chk: + case LibFunc_mempcpy_chk: case LibFunc_memmove_chk: --NumParams; if (!IsSizeTTy(FTy.getParamType(NumParams))) diff --git a/llvm/lib/Transforms/Utils/BuildLibCalls.cpp b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp index 2a0cdf6..86e9b48 100644 --- a/llvm/lib/Transforms/Utils/BuildLibCalls.cpp +++ b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp @@ -1076,6 +1076,15 @@ Value *llvm::emitMemCpyChk(Value *Dst, Value *Src, Value *Len, Value *ObjSize, return CI; } +Value *llvm::emitMemPCpy(Value *Dst, Value *Src, Value *Len, IRBuilderBase &B, + const DataLayout &DL, const TargetLibraryInfo *TLI) { + LLVMContext &Context = B.GetInsertBlock()->getContext(); + return emitLibCall( + LibFunc_mempcpy, B.getInt8PtrTy(), + {B.getInt8PtrTy(), B.getInt8PtrTy(), DL.getIntPtrType(Context)}, + {Dst, Src, Len}, B, TLI); +} + Value *llvm::emitMemChr(Value *Ptr, Value *Val, Value *Len, IRBuilderBase &B, const DataLayout &DL, const TargetLibraryInfo *TLI) { LLVMContext &Context = B.GetInsertBlock()->getContext(); diff --git a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp index bcda3f3..a904d25 100644 --- a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -3292,6 +3292,19 @@ Value *FortifiedLibCallSimplifier::optimizeMemSetChk(CallInst *CI, return nullptr; } +Value *FortifiedLibCallSimplifier::optimizeMemPCpyChk(CallInst *CI, + IRBuilderBase &B) { + const DataLayout &DL = CI->getModule()->getDataLayout(); + if (isFortifiedCallFoldable(CI, 3, 2)) + if (Value *Call = emitMemPCpy(CI->getArgOperand(0), CI->getArgOperand(1), + CI->getArgOperand(2), B, DL, TLI)) { + CallInst *NewCI = cast(Call); + NewCI->setAttributes(CI->getAttributes()); + return NewCI; + } + return nullptr; +} + Value *FortifiedLibCallSimplifier::optimizeStrpCpyChk(CallInst *CI, IRBuilderBase &B, LibFunc Func) { @@ -3481,6 +3494,8 @@ Value *FortifiedLibCallSimplifier::optimizeCall(CallInst *CI, switch (Func) { case LibFunc_memcpy_chk: return optimizeMemCpyChk(CI, Builder); + case LibFunc_mempcpy_chk: + return optimizeMemPCpyChk(CI, Builder); case LibFunc_memmove_chk: return optimizeMemMoveChk(CI, Builder); case LibFunc_memset_chk: diff --git a/llvm/test/Transforms/InstCombine/fortify-folding.ll b/llvm/test/Transforms/InstCombine/fortify-folding.ll index 2602640..ea29ecc 100644 --- a/llvm/test/Transforms/InstCombine/fortify-folding.ll +++ b/llvm/test/Transforms/InstCombine/fortify-folding.ll @@ -31,6 +31,28 @@ define i8* @test_not_memccpy() { ret i8* %ret } +define i8* @test_mempcpy() { +; CHECK-LABEL: @test_mempcpy( +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* nonnull align 1 dereferenceable(15) getelementptr inbounds ([60 x i8], [60 x i8]* @a, i64 0, i64 0), i8* nonnull align 1 dereferenceable(15) getelementptr inbounds ([60 x i8], [60 x i8]* @b, i64 0, i64 0), i64 15, i1 false) +; CHECK-NEXT: ret i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i64 0, i64 15) +; + %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0 + %src = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0 + %ret = call i8* @__mempcpy_chk(i8* %dst, i8* %src, i64 15, i64 -1) + ret i8* %ret +} + +define i8* @test_not_mempcpy() { +; CHECK-LABEL: @test_not_mempcpy( +; CHECK-NEXT: [[RET:%.*]] = call i8* @__mempcpy_chk(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i64 0, i64 0), i8* getelementptr inbounds ([60 x i8], [60 x i8]* @b, i64 0, i64 0), i64 60, i64 59) +; CHECK-NEXT: ret i8* [[RET]] +; + %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0 + %src = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0 + %ret = call i8* @__mempcpy_chk(i8* %dst, i8* %src, i64 60, i64 59) + ret i8* %ret +} + define i32 @test_snprintf() { ; CHECK-LABEL: @test_snprintf( ; CHECK-NEXT: [[SNPRINTF:%.*]] = call i32 (i8*, i64, i8*, ...) @snprintf(i8* nonnull dereferenceable(1) getelementptr inbounds ([60 x i8], [60 x i8]* @a, i64 0, i64 0), i64 60, i8* getelementptr inbounds ([60 x i8], [60 x i8]* @b, i64 0, i64 0)) @@ -219,6 +241,7 @@ define i32 @test_not_vsprintf() { ret i32 %ret } +declare i8* @__mempcpy_chk(i8*, i8*, i64, i64) declare i8* @__memccpy_chk(i8*, i8*, i32, i64, i64) declare i32 @__snprintf_chk(i8*, i64, i32, i64, i8*, ...) declare i32 @__sprintf_chk(i8*, i32, i64, i8*, ...) -- 2.7.4