From bf060d4e97c1a9cecf9ff2c68c641cd528129e44 Mon Sep 17 00:00:00 2001 From: Eric Fiselier Date: Wed, 4 Apr 2018 19:01:51 +0000 Subject: [PATCH] [Analysis] Support aligned new/delete functions. Summary: Clang's __builtin_operator_new/delete was recently taught about the aligned allocation overloads (r328134). This patch makes LLVM aware of them as well. This allows the compiler to perform certain optimizations including eliding new/delete calls. Reviewers: rsmith, majnemer, dblaikie, vsk, bkramer Reviewed By: bkramer Subscribers: ckennelly, llvm-commits Differential Revision: https://reviews.llvm.org/D44769 llvm-svn: 329218 --- include/llvm/Analysis/TargetLibraryInfo.def | 36 +++++++++++++++++ lib/Analysis/MemoryBuiltins.cpp | 17 ++++++++ lib/Analysis/TargetLibraryInfo.cpp | 28 +++++++++++++ .../InstCombine/malloc-free-delete.ll | 40 +++++++++++++++++++ unittests/Analysis/TargetLibraryInfoTest.cpp | 12 ++++++ 5 files changed, 133 insertions(+) diff --git a/include/llvm/Analysis/TargetLibraryInfo.def b/include/llvm/Analysis/TargetLibraryInfo.def index a461ed813b9..154556b0bcb 100644 --- a/include/llvm/Analysis/TargetLibraryInfo.def +++ b/include/llvm/Analysis/TargetLibraryInfo.def @@ -119,6 +119,12 @@ TLI_DEFINE_STRING_INTERNAL("_ZdaPv") /// void operator delete[](void*, nothrow); TLI_DEFINE_ENUM_INTERNAL(ZdaPvRKSt9nothrow_t) TLI_DEFINE_STRING_INTERNAL("_ZdaPvRKSt9nothrow_t") +/// void operator delete[](void*, align_val_t); +TLI_DEFINE_ENUM_INTERNAL(ZdaPvSt11align_val_t) +TLI_DEFINE_STRING_INTERNAL("_ZdaPvSt11align_val_t") +/// void operator delete[](void*, align_val_t, nothrow) +TLI_DEFINE_ENUM_INTERNAL(ZdaPvSt11align_val_tRKSt9nothrow_t) +TLI_DEFINE_STRING_INTERNAL("_ZdaPvSt11align_val_tRKSt9nothrow_t") /// void operator delete[](void*, unsigned int); TLI_DEFINE_ENUM_INTERNAL(ZdaPvj) TLI_DEFINE_STRING_INTERNAL("_ZdaPvj") @@ -131,6 +137,12 @@ TLI_DEFINE_STRING_INTERNAL("_ZdlPv") /// void operator delete(void*, nothrow); TLI_DEFINE_ENUM_INTERNAL(ZdlPvRKSt9nothrow_t) TLI_DEFINE_STRING_INTERNAL("_ZdlPvRKSt9nothrow_t") +/// void operator delete(void*, align_val_t) +TLI_DEFINE_ENUM_INTERNAL(ZdlPvSt11align_val_t) +TLI_DEFINE_STRING_INTERNAL("_ZdlPvSt11align_val_t") +/// void operator delete(void*, align_val_t, nothrow) +TLI_DEFINE_ENUM_INTERNAL(ZdlPvSt11align_val_tRKSt9nothrow_t) +TLI_DEFINE_STRING_INTERNAL("_ZdlPvSt11align_val_tRKSt9nothrow_t") /// void operator delete(void*, unsigned int); TLI_DEFINE_ENUM_INTERNAL(ZdlPvj) TLI_DEFINE_STRING_INTERNAL("_ZdlPvj") @@ -143,24 +155,48 @@ TLI_DEFINE_STRING_INTERNAL("_Znaj") /// void *new[](unsigned int, nothrow); TLI_DEFINE_ENUM_INTERNAL(ZnajRKSt9nothrow_t) TLI_DEFINE_STRING_INTERNAL("_ZnajRKSt9nothrow_t") +/// void *new[](unsigned int, align_val_t) +TLI_DEFINE_ENUM_INTERNAL(ZnajSt11align_val_t) +TLI_DEFINE_STRING_INTERNAL("_ZnajSt11align_val_t") +/// void *new[](unsigned int, align_val_t, nothrow) +TLI_DEFINE_ENUM_INTERNAL(ZnajSt11align_val_tRKSt9nothrow_t) +TLI_DEFINE_STRING_INTERNAL("_ZnajSt11align_val_tRKSt9nothrow_t") /// void *new[](unsigned long); TLI_DEFINE_ENUM_INTERNAL(Znam) TLI_DEFINE_STRING_INTERNAL("_Znam") /// void *new[](unsigned long, nothrow); TLI_DEFINE_ENUM_INTERNAL(ZnamRKSt9nothrow_t) TLI_DEFINE_STRING_INTERNAL("_ZnamRKSt9nothrow_t") +/// void *new[](unsigned long, align_val_t) +TLI_DEFINE_ENUM_INTERNAL(ZnamSt11align_val_t) +TLI_DEFINE_STRING_INTERNAL("_ZnamSt11align_val_t") +/// void *new[](unsigned long, align_val_t, nothrow) +TLI_DEFINE_ENUM_INTERNAL(ZnamSt11align_val_tRKSt9nothrow_t) +TLI_DEFINE_STRING_INTERNAL("_ZnamSt11align_val_tRKSt9nothrow_t") /// void *new(unsigned int); TLI_DEFINE_ENUM_INTERNAL(Znwj) TLI_DEFINE_STRING_INTERNAL("_Znwj") /// void *new(unsigned int, nothrow); TLI_DEFINE_ENUM_INTERNAL(ZnwjRKSt9nothrow_t) TLI_DEFINE_STRING_INTERNAL("_ZnwjRKSt9nothrow_t") +/// void *new(unsigned int, align_val_t) +TLI_DEFINE_ENUM_INTERNAL(ZnwjSt11align_val_t) +TLI_DEFINE_STRING_INTERNAL("_ZnwjSt11align_val_t") +/// void *new(unsigned int, align_val_t, nothrow) +TLI_DEFINE_ENUM_INTERNAL(ZnwjSt11align_val_tRKSt9nothrow_t) +TLI_DEFINE_STRING_INTERNAL("_ZnwjSt11align_val_tRKSt9nothrow_t") /// void *new(unsigned long); TLI_DEFINE_ENUM_INTERNAL(Znwm) TLI_DEFINE_STRING_INTERNAL("_Znwm") /// void *new(unsigned long, nothrow); TLI_DEFINE_ENUM_INTERNAL(ZnwmRKSt9nothrow_t) TLI_DEFINE_STRING_INTERNAL("_ZnwmRKSt9nothrow_t") +/// void *new(unsigned long, align_val_t) +TLI_DEFINE_ENUM_INTERNAL(ZnwmSt11align_val_t) +TLI_DEFINE_STRING_INTERNAL("_ZnwmSt11align_val_t") +/// void *new(unsigned long, align_val_t, nothrow) +TLI_DEFINE_ENUM_INTERNAL(ZnwmSt11align_val_tRKSt9nothrow_t) +TLI_DEFINE_STRING_INTERNAL("_ZnwmSt11align_val_tRKSt9nothrow_t") /// double __acos_finite(double x); TLI_DEFINE_ENUM_INTERNAL(acos_finite) TLI_DEFINE_STRING_INTERNAL("__acos_finite") diff --git a/lib/Analysis/MemoryBuiltins.cpp b/lib/Analysis/MemoryBuiltins.cpp index 8c0c374d530..2e5197a8ff1 100644 --- a/lib/Analysis/MemoryBuiltins.cpp +++ b/lib/Analysis/MemoryBuiltins.cpp @@ -75,12 +75,24 @@ static const std::pair AllocationFnData[] = { {LibFunc_valloc, {MallocLike, 1, 0, -1}}, {LibFunc_Znwj, {OpNewLike, 1, 0, -1}}, // new(unsigned int) {LibFunc_ZnwjRKSt9nothrow_t, {MallocLike, 2, 0, -1}}, // new(unsigned int, nothrow) + {LibFunc_ZnwjSt11align_val_t, {OpNewLike, 2, 0, -1}}, // new(unsigned int, align_val_t) + {LibFunc_ZnwjSt11align_val_tRKSt9nothrow_t, // new(unsigned int, align_val_t, nothrow) + {MallocLike, 3, 0, -1}}, {LibFunc_Znwm, {OpNewLike, 1, 0, -1}}, // new(unsigned long) {LibFunc_ZnwmRKSt9nothrow_t, {MallocLike, 2, 0, -1}}, // new(unsigned long, nothrow) + {LibFunc_ZnwmSt11align_val_t, {OpNewLike, 2, 0, -1}}, // new(unsigned long, align_val_t) + {LibFunc_ZnwmSt11align_val_tRKSt9nothrow_t, // new(unsigned long, align_val_t, nothrow) + {MallocLike, 3, 0, -1}}, {LibFunc_Znaj, {OpNewLike, 1, 0, -1}}, // new[](unsigned int) {LibFunc_ZnajRKSt9nothrow_t, {MallocLike, 2, 0, -1}}, // new[](unsigned int, nothrow) + {LibFunc_ZnajSt11align_val_t, {OpNewLike, 2, 0, -1}}, // new[](unsigned int, align_val_t) + {LibFunc_ZnajSt11align_val_tRKSt9nothrow_t, // new[](unsigned int, align_val_t, nothrow) + {MallocLike, 3, 0, -1}}, {LibFunc_Znam, {OpNewLike, 1, 0, -1}}, // new[](unsigned long) {LibFunc_ZnamRKSt9nothrow_t, {MallocLike, 2, 0, -1}}, // new[](unsigned long, nothrow) + {LibFunc_ZnamSt11align_val_t, {OpNewLike, 2, 0, -1}}, // new[](unsigned long, align_val_t) + {LibFunc_ZnamSt11align_val_tRKSt9nothrow_t, // new[](unsigned long, align_val_t, nothrow) + {MallocLike, 3, 0, -1}}, {LibFunc_msvc_new_int, {OpNewLike, 1, 0, -1}}, // new(unsigned int) {LibFunc_msvc_new_int_nothrow, {MallocLike, 2, 0, -1}}, // new(unsigned int, nothrow) {LibFunc_msvc_new_longlong, {OpNewLike, 1, 0, -1}}, // new(unsigned long long) @@ -372,9 +384,11 @@ const CallInst *llvm::isFreeCall(const Value *I, const TargetLibraryInfo *TLI) { else if (TLIFn == LibFunc_ZdlPvj || // delete(void*, uint) TLIFn == LibFunc_ZdlPvm || // delete(void*, ulong) TLIFn == LibFunc_ZdlPvRKSt9nothrow_t || // delete(void*, nothrow) + TLIFn == LibFunc_ZdlPvSt11align_val_t || // delete(void*, align_val_t) TLIFn == LibFunc_ZdaPvj || // delete[](void*, uint) TLIFn == LibFunc_ZdaPvm || // delete[](void*, ulong) TLIFn == LibFunc_ZdaPvRKSt9nothrow_t || // delete[](void*, nothrow) + TLIFn == LibFunc_ZdaPvSt11align_val_t || // delete[](void*, align_val_t) TLIFn == LibFunc_msvc_delete_ptr32_int || // delete(void*, uint) TLIFn == LibFunc_msvc_delete_ptr64_longlong || // delete(void*, ulonglong) TLIFn == LibFunc_msvc_delete_ptr32_nothrow || // delete(void*, nothrow) @@ -384,6 +398,9 @@ const CallInst *llvm::isFreeCall(const Value *I, const TargetLibraryInfo *TLI) { TLIFn == LibFunc_msvc_delete_array_ptr32_nothrow || // delete[](void*, nothrow) TLIFn == LibFunc_msvc_delete_array_ptr64_nothrow) // delete[](void*, nothrow) ExpectedNumParams = 2; + else if (TLIFn == LibFunc_ZdaPvSt11align_val_tRKSt9nothrow_t || // delete(void*, align_val_t, nothrow) + TLIFn == LibFunc_ZdlPvSt11align_val_tRKSt9nothrow_t) // delete[](void*, align_val_t, nothrow) + ExpectedNumParams = 3; else return nullptr; diff --git a/lib/Analysis/TargetLibraryInfo.cpp b/lib/Analysis/TargetLibraryInfo.cpp index c605c91c11c..ff6aae8b5ec 100644 --- a/lib/Analysis/TargetLibraryInfo.cpp +++ b/lib/Analysis/TargetLibraryInfo.cpp @@ -992,8 +992,26 @@ bool TargetLibraryInfoImpl::isValidProtoForLibFunc(const FunctionType &FTy, case LibFunc_msvc_new_array_int_nothrow: // new[](unsigned long long, nothrow); case LibFunc_msvc_new_array_longlong_nothrow: + // new(unsigned int, align_val_t) + case LibFunc_ZnwjSt11align_val_t: + // new(unsigned long, align_val_t) + case LibFunc_ZnwmSt11align_val_t: + // new[](unsigned int, align_val_t) + case LibFunc_ZnajSt11align_val_t: + // new[](unsigned long, align_val_t) + case LibFunc_ZnamSt11align_val_t: return (NumParams == 2 && FTy.getReturnType()->isPointerTy()); + // new(unsigned int, align_val_t, nothrow) + case LibFunc_ZnwjSt11align_val_tRKSt9nothrow_t: + // new(unsigned long, align_val_t, nothrow) + case LibFunc_ZnwmSt11align_val_tRKSt9nothrow_t: + // new[](unsigned int, align_val_t, nothrow) + case LibFunc_ZnajSt11align_val_tRKSt9nothrow_t: + // new[](unsigned long, align_val_t, nothrow) + case LibFunc_ZnamSt11align_val_tRKSt9nothrow_t: + return (NumParams == 3 && FTy.getReturnType()->isPointerTy()); + // void operator delete[](void*); case LibFunc_ZdaPv: // void operator delete(void*); @@ -1020,6 +1038,10 @@ bool TargetLibraryInfoImpl::isValidProtoForLibFunc(const FunctionType &FTy, case LibFunc_ZdlPvj: // void operator delete(void*, unsigned long); case LibFunc_ZdlPvm: + // void operator delete(void*, align_val_t) + case LibFunc_ZdlPvSt11align_val_t: + // void operator delete[](void*, align_val_t) + case LibFunc_ZdaPvSt11align_val_t: // void operator delete[](void*, unsigned int); case LibFunc_msvc_delete_array_ptr32_int: // void operator delete[](void*, nothrow); @@ -1038,6 +1060,12 @@ bool TargetLibraryInfoImpl::isValidProtoForLibFunc(const FunctionType &FTy, case LibFunc_msvc_delete_ptr64_nothrow: return (NumParams == 2 && FTy.getParamType(0)->isPointerTy()); + // void operator delete(void*, align_val_t, nothrow) + case LibFunc_ZdlPvSt11align_val_tRKSt9nothrow_t: + // void operator delete[](void*, align_val_t, nothrow) + case LibFunc_ZdaPvSt11align_val_tRKSt9nothrow_t: + return (NumParams == 3 && FTy.getParamType(0)->isPointerTy()); + case LibFunc_memset_pattern16: return (!FTy.isVarArg() && NumParams == 3 && FTy.getParamType(0)->isPointerTy() && diff --git a/test/Transforms/InstCombine/malloc-free-delete.ll b/test/Transforms/InstCombine/malloc-free-delete.ll index 04d3448fb0b..e66151025b5 100644 --- a/test/Transforms/InstCombine/malloc-free-delete.ll +++ b/test/Transforms/InstCombine/malloc-free-delete.ll @@ -173,9 +173,33 @@ define linkonce void @_ZdaPvj(i8* %p, i32) nobuiltin { ret void } + +; new(size_t, align_val_t) +declare i8* @_ZnwmSt11align_val_t(i64, i64) nobuiltin +declare i8* @_ZnwjSt11align_val_t(i32, i32) nobuiltin +; new[](size_t, align_val_t) +declare i8* @_ZnamSt11align_val_t(i64, i64) nobuiltin +declare i8* @_ZnajSt11align_val_t(i32, i32) nobuiltin +; new(size_t, align_val_t, nothrow) +declare i8* @_ZnwmSt11align_val_tRKSt9nothrow_t(i64, i64, i8*) nobuiltin +declare i8* @_ZnwjSt11align_val_tRKSt9nothrow_t(i32, i32, i8*) nobuiltin +; new[](size_t, align_val_t, nothrow) +declare i8* @_ZnamSt11align_val_tRKSt9nothrow_t(i64, i64, i8*) nobuiltin +declare i8* @_ZnajSt11align_val_tRKSt9nothrow_t(i32, i32, i8*) nobuiltin +; delete(void*, align_val_t) +declare void @_ZdlPvSt11align_val_t(i8*, i64) nobuiltin +; delete[](void*, align_val_t) +declare void @_ZdaPvSt11align_val_t(i8*, i64) nobuiltin +; delete(void*, align_val_t, nothrow) +declare void @_ZdlPvSt11align_val_tRKSt9nothrow_t(i8*, i64, i8*) nobuiltin +; delete[](void*, align_val_t, nothrow) +declare void @_ZdaPvSt11align_val_tRKSt9nothrow_t(i8*, i64, i8*) nobuiltin + + ; CHECK-LABEL: @test8( define void @test8() { ; CHECK-NOT: call + %nt = alloca i8 %nw = call i8* @_Znwm(i64 32) builtin call void @_ZdlPv(i8* %nw) builtin %na = call i8* @_Znam(i64 32) builtin @@ -188,6 +212,22 @@ define void @test8() { call void @_ZdaPvm(i8* %nam, i64 32) builtin %naj = call i8* @_Znaj(i32 32) builtin call void @_ZdaPvj(i8* %naj, i32 32) builtin + %nwa = call i8* @_ZnwmSt11align_val_t(i64 32, i64 8) builtin + call void @_ZdlPvSt11align_val_t(i8* %nwa, i64 8) builtin + %naa = call i8* @_ZnamSt11align_val_t(i64 32, i64 8) builtin + call void @_ZdaPvSt11align_val_t(i8* %naa, i64 8) builtin + %nwja = call i8* @_ZnwjSt11align_val_t(i32 32, i32 8) builtin + call void @_ZdlPvSt11align_val_t(i8* %nwja, i64 8) builtin + %naja = call i8* @_ZnajSt11align_val_t(i32 32, i32 8) builtin + call void @_ZdaPvSt11align_val_t(i8* %naja, i64 8) builtin + %nwat = call i8* @_ZnwmSt11align_val_tRKSt9nothrow_t(i64 32, i64 8, i8* %nt) builtin + call void @_ZdlPvSt11align_val_tRKSt9nothrow_t(i8* %nwat, i64 8, i8* %nt) builtin + %naat = call i8* @_ZnamSt11align_val_tRKSt9nothrow_t(i64 32, i64 8, i8* %nt) builtin + call void @_ZdaPvSt11align_val_tRKSt9nothrow_t(i8* %naat, i64 8, i8* %nt) builtin + %nwjat = call i8* @_ZnwjSt11align_val_tRKSt9nothrow_t(i32 32, i32 8, i8* %nt) builtin + call void @_ZdlPvSt11align_val_tRKSt9nothrow_t(i8* %nwjat, i64 8, i8* %nt) builtin + %najat = call i8* @_ZnajSt11align_val_tRKSt9nothrow_t(i32 32, i32 8, i8* %nt) builtin + call void @_ZdaPvSt11align_val_tRKSt9nothrow_t(i8* %najat, i64 8, i8* %nt) builtin ret void } diff --git a/unittests/Analysis/TargetLibraryInfoTest.cpp b/unittests/Analysis/TargetLibraryInfoTest.cpp index ef558a434c7..0c8ba9ee77b 100644 --- a/unittests/Analysis/TargetLibraryInfoTest.cpp +++ b/unittests/Analysis/TargetLibraryInfoTest.cpp @@ -386,20 +386,32 @@ TEST_F(TargetLibraryInfoTest, ValidProto) { "declare void @_ZdaPv(i8*)\n" "declare void @_ZdaPvRKSt9nothrow_t(i8*, %struct*)\n" + "declare void @_ZdaPvSt11align_val_t(i8*, i64)\n" + "declare void @_ZdaPvSt11align_val_tRKSt9nothrow_t(i8*, i64, %struct*)\n" "declare void @_ZdaPvj(i8*, i32)\n" "declare void @_ZdaPvm(i8*, i64)\n" "declare void @_ZdlPv(i8*)\n" "declare void @_ZdlPvRKSt9nothrow_t(i8*, %struct*)\n" + "declare void @_ZdlPvSt11align_val_t(i8*, i64)\n" + "declare void @_ZdlPvSt11align_val_tRKSt9nothrow_t(i8*, i64, %struct*)\n" "declare void @_ZdlPvj(i8*, i32)\n" "declare void @_ZdlPvm(i8*, i64)\n" "declare i8* @_Znaj(i32)\n" "declare i8* @_ZnajRKSt9nothrow_t(i32, %struct*)\n" + "declare i8* @_ZnajSt11align_val_t(i32, i32)\n" + "declare i8* @_ZnajSt11align_val_tRKSt9nothrow_t(i32, i32, %struct*)\n" "declare i8* @_Znam(i64)\n" "declare i8* @_ZnamRKSt9nothrow_t(i64, %struct*)\n" + "declare i8* @_ZnamSt11align_val_t(i64, i64)\n" + "declare i8* @_ZnamSt11align_val_tRKSt9nothrow_t(i64, i64, %struct*)\n" "declare i8* @_Znwj(i32)\n" "declare i8* @_ZnwjRKSt9nothrow_t(i32, %struct*)\n" + "declare i8* @_ZnwjSt11align_val_t(i32, i32)\n" + "declare i8* @_ZnwjSt11align_val_tRKSt9nothrow_t(i32, i32, %struct*)\n" "declare i8* @_Znwm(i64)\n" "declare i8* @_ZnwmRKSt9nothrow_t(i64, %struct*)\n" + "declare i8* @_ZnwmSt11align_val_t(i64, i64)\n" + "declare i8* @_ZnwmSt11align_val_tRKSt9nothrow_t(i64, i64, %struct*)\n" "declare void @\"??3@YAXPEAX@Z\"(i8*)\n" "declare void @\"??3@YAXPEAXAEBUnothrow_t@std@@@Z\"(i8*, %struct*)\n"