[llvm] a35206d - [MemProf] Optionally pass hot/cold hints to operator new

Teresa Johnson via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 19 13:34:22 PDT 2023


Author: Teresa Johnson
Date: 2023-04-19T13:33:46-07:00
New Revision: a35206d78280e0ebcf48cd21bc5fff5c3b9c73fa

URL: https://github.com/llvm/llvm-project/commit/a35206d78280e0ebcf48cd21bc5fff5c3b9c73fa
DIFF: https://github.com/llvm/llvm-project/commit/a35206d78280e0ebcf48cd21bc5fff5c3b9c73fa.diff

LOG: [MemProf] Optionally pass hot/cold hints to operator new

Optionally (off by default) replace operator new() calls marked with a
hot or cold memprof attribute with an operator new() call that takes a
hot_cold_t parameter.

Currently this is supported by the open source version of tcmalloc, see:
https://github.com/google/tcmalloc/blob/master/tcmalloc/new_extension.h

Differential Revision: https://reviews.llvm.org/D148718

Added: 
    llvm/test/Transforms/InstCombine/simplify-libcalls-new.ll

Modified: 
    llvm/include/llvm/Analysis/TargetLibraryInfo.def
    llvm/include/llvm/Transforms/Utils/BuildLibCalls.h
    llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h
    llvm/lib/Analysis/MemoryBuiltins.cpp
    llvm/lib/Analysis/TargetLibraryInfo.cpp
    llvm/lib/Transforms/Utils/BuildLibCalls.cpp
    llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
    llvm/test/tools/llvm-tli-checker/ps4-tli-check.yaml
    llvm/unittests/Analysis/TargetLibraryInfoTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Analysis/TargetLibraryInfo.def b/llvm/include/llvm/Analysis/TargetLibraryInfo.def
index 5f6af3514fc24..72a32a5b37d62 100644
--- a/llvm/include/llvm/Analysis/TargetLibraryInfo.def
+++ b/llvm/include/llvm/Analysis/TargetLibraryInfo.def
@@ -256,21 +256,46 @@ TLI_DEFINE_ENUM_INTERNAL(Znam)
 TLI_DEFINE_STRING_INTERNAL("_Znam")
 TLI_DEFINE_SIG_INTERNAL(Ptr, Long)
 
+/// void *operator new[](unsigned long, hot_cold_t)
+/// Currently this and other operator new interfaces that take a hot_cold_t
+/// hint are supported by the open source version of tcmalloc, see:
+/// https://github.com/google/tcmalloc/blob/master/tcmalloc/new_extension.h
+/// and for the definition of the hot_cold_t parameter see:
+/// https://github.com/google/tcmalloc/blob/master/tcmalloc/malloc_extension.h
+TLI_DEFINE_ENUM_INTERNAL(Znam10hot_cold_t)
+TLI_DEFINE_STRING_INTERNAL("_Znam10hot_cold_t")
+TLI_DEFINE_SIG_INTERNAL(Ptr, Long, Bool)
+
 /// void *operator new[](unsigned long, const std::nothrow_t&);
 TLI_DEFINE_ENUM_INTERNAL(ZnamRKSt9nothrow_t)
 TLI_DEFINE_STRING_INTERNAL("_ZnamRKSt9nothrow_t")
 TLI_DEFINE_SIG_INTERNAL(Ptr, Long, Ptr)
 
+/// void *operator new[](unsigned long, const std::nothrow_t&, hot_cold_t)
+TLI_DEFINE_ENUM_INTERNAL(ZnamRKSt9nothrow_t10hot_cold_t)
+TLI_DEFINE_STRING_INTERNAL("_ZnamRKSt9nothrow_t10hot_cold_t")
+TLI_DEFINE_SIG_INTERNAL(Ptr, Long, Ptr, Bool)
+
 /// void *operator new[](unsigned long, std::align_val_t)
 TLI_DEFINE_ENUM_INTERNAL(ZnamSt11align_val_t)
 TLI_DEFINE_STRING_INTERNAL("_ZnamSt11align_val_t")
 TLI_DEFINE_SIG_INTERNAL(Ptr, Long, Long)
 
+/// void *operator new[](unsigned long, std::align_val_t, hot_cold_t)
+TLI_DEFINE_ENUM_INTERNAL(ZnamSt11align_val_t10hot_cold_t)
+TLI_DEFINE_STRING_INTERNAL("_ZnamSt11align_val_t10hot_cold_t")
+TLI_DEFINE_SIG_INTERNAL(Ptr, Long, Long, Bool)
+
 /// void *operator new[](unsigned long, std::align_val_t, const std::nothrow_t&)
 TLI_DEFINE_ENUM_INTERNAL(ZnamSt11align_val_tRKSt9nothrow_t)
 TLI_DEFINE_STRING_INTERNAL("_ZnamSt11align_val_tRKSt9nothrow_t")
 TLI_DEFINE_SIG_INTERNAL(Ptr, Long, Long, Ptr)
 
+/// void *operator new[](unsigned long, std::align_val_t, const std::nothrow_t&, hot_cold_t)
+TLI_DEFINE_ENUM_INTERNAL(ZnamSt11align_val_tRKSt9nothrow_t10hot_cold_t)
+TLI_DEFINE_STRING_INTERNAL("_ZnamSt11align_val_tRKSt9nothrow_t10hot_cold_t")
+TLI_DEFINE_SIG_INTERNAL(Ptr, Long, Long, Ptr, Bool)
+
 /// void *operator new(unsigned int);
 TLI_DEFINE_ENUM_INTERNAL(Znwj)
 TLI_DEFINE_STRING_INTERNAL("_Znwj")
@@ -296,21 +321,41 @@ TLI_DEFINE_ENUM_INTERNAL(Znwm)
 TLI_DEFINE_STRING_INTERNAL("_Znwm")
 TLI_DEFINE_SIG_INTERNAL(Ptr, Long)
 
+/// void *operator new(unsigned long, hot_cold_t)
+TLI_DEFINE_ENUM_INTERNAL(Znwm10hot_cold_t)
+TLI_DEFINE_STRING_INTERNAL("_Znwm10hot_cold_t")
+TLI_DEFINE_SIG_INTERNAL(Ptr, Long, Bool)
+
 /// void *operator new(unsigned long, const std::nothrow_t&);
 TLI_DEFINE_ENUM_INTERNAL(ZnwmRKSt9nothrow_t)
 TLI_DEFINE_STRING_INTERNAL("_ZnwmRKSt9nothrow_t")
 TLI_DEFINE_SIG_INTERNAL(Ptr, Long, Ptr)
 
+/// void *operator new(unsigned long, const std::nothrow_t&, hot_cold_t)
+TLI_DEFINE_ENUM_INTERNAL(ZnwmRKSt9nothrow_t10hot_cold_t)
+TLI_DEFINE_STRING_INTERNAL("_ZnwmRKSt9nothrow_t10hot_cold_t")
+TLI_DEFINE_SIG_INTERNAL(Ptr, Long, Ptr, Bool)
+
 /// void *operator new(unsigned long, std::align_val_t)
 TLI_DEFINE_ENUM_INTERNAL(ZnwmSt11align_val_t)
 TLI_DEFINE_STRING_INTERNAL("_ZnwmSt11align_val_t")
 TLI_DEFINE_SIG_INTERNAL(Ptr, Long, Long)
 
+/// void *operator new(unsigned long, std::align_val_t, hot_cold_t)
+TLI_DEFINE_ENUM_INTERNAL(ZnwmSt11align_val_t10hot_cold_t)
+TLI_DEFINE_STRING_INTERNAL("_ZnwmSt11align_val_t10hot_cold_t")
+TLI_DEFINE_SIG_INTERNAL(Ptr, Long, Long, Bool)
+
 /// void *operator new(unsigned long, std::align_val_t, const std::nothrow_t&)
 TLI_DEFINE_ENUM_INTERNAL(ZnwmSt11align_val_tRKSt9nothrow_t)
 TLI_DEFINE_STRING_INTERNAL("_ZnwmSt11align_val_tRKSt9nothrow_t")
 TLI_DEFINE_SIG_INTERNAL(Ptr, Long, Long, Ptr)
 
+/// void *operator new(unsigned long, std::align_val_t, const std::nothrow_t&, hot_cold_t)
+TLI_DEFINE_ENUM_INTERNAL(ZnwmSt11align_val_tRKSt9nothrow_t10hot_cold_t)
+TLI_DEFINE_STRING_INTERNAL("_ZnwmSt11align_val_tRKSt9nothrow_t10hot_cold_t")
+TLI_DEFINE_SIG_INTERNAL(Ptr, Long, Long, Ptr, Bool)
+
 /// double __acos_finite(double x);
 TLI_DEFINE_ENUM_INTERNAL(acos_finite)
 TLI_DEFINE_STRING_INTERNAL("__acos_finite")

diff  --git a/llvm/include/llvm/Transforms/Utils/BuildLibCalls.h b/llvm/include/llvm/Transforms/Utils/BuildLibCalls.h
index bb1cb07342d46..429970cbe3042 100644
--- a/llvm/include/llvm/Transforms/Utils/BuildLibCalls.h
+++ b/llvm/include/llvm/Transforms/Utils/BuildLibCalls.h
@@ -248,6 +248,21 @@ namespace llvm {
   /// Emit a call to the calloc function.
   Value *emitCalloc(Value *Num, Value *Size, IRBuilderBase &B,
                     const TargetLibraryInfo &TLI);
+
+  /// Emit a call to the hot/cold operator new function.
+  Value *emitHotColdNew(Value *Num, IRBuilderBase &B,
+                        const TargetLibraryInfo *TLI, LibFunc NewFunc,
+                        uint8_t HotCold);
+  Value *emitHotColdNewNoThrow(Value *Num, Value *NoThrow, IRBuilderBase &B,
+                               const TargetLibraryInfo *TLI, LibFunc NewFunc,
+                               uint8_t HotCold);
+  Value *emitHotColdNewAligned(Value *Num, Value *Align, IRBuilderBase &B,
+                               const TargetLibraryInfo *TLI, LibFunc NewFunc,
+                               uint8_t HotCold);
+  Value *emitHotColdNewAlignedNoThrow(Value *Num, Value *Align, Value *NoThrow,
+                                      IRBuilderBase &B,
+                                      const TargetLibraryInfo *TLI,
+                                      LibFunc NewFunc, uint8_t HotCold);
 }
 
 #endif

diff  --git a/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h b/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h
index 11c971754a9e6..9269216d06789 100644
--- a/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h
+++ b/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h
@@ -181,6 +181,7 @@ class LibCallSimplifier {
   Value *optimizeMemMove(CallInst *CI, IRBuilderBase &B);
   Value *optimizeMemSet(CallInst *CI, IRBuilderBase &B);
   Value *optimizeRealloc(CallInst *CI, IRBuilderBase &B);
+  Value *optimizeNew(CallInst *CI, IRBuilderBase &B, LibFunc &Func);
   Value *optimizeWcslen(CallInst *CI, IRBuilderBase &B);
   Value *optimizeBCopy(CallInst *CI, IRBuilderBase &B);
 

diff  --git a/llvm/lib/Analysis/MemoryBuiltins.cpp b/llvm/lib/Analysis/MemoryBuiltins.cpp
index 4d818bb9ad055..116a9222a241a 100644
--- a/llvm/lib/Analysis/MemoryBuiltins.cpp
+++ b/llvm/lib/Analysis/MemoryBuiltins.cpp
@@ -115,17 +115,25 @@ static const std::pair<LibFunc, AllocFnsTy> AllocationFnData[] = {
     {LibFunc_ZnwjSt11align_val_t,               {OpNewLike,        2,  0, -1,  1, MallocFamily::CPPNewAligned}},      // new(unsigned int, align_val_t)
     {LibFunc_ZnwjSt11align_val_tRKSt9nothrow_t, {MallocLike,       3,  0, -1,  1, MallocFamily::CPPNewAligned}},      // new(unsigned int, align_val_t, nothrow)
     {LibFunc_Znwm,                              {OpNewLike,        1,  0, -1, -1, MallocFamily::CPPNew}},             // new(unsigned long)
+    {LibFunc_Znwm10hot_cold_t,                  {OpNewLike,        2, 0,  -1, -1, MallocFamily::CPPNew}},             // new(unsigned long, hot_cold_t)
     {LibFunc_ZnwmRKSt9nothrow_t,                {MallocLike,       2,  0, -1, -1, MallocFamily::CPPNew}},             // new(unsigned long, nothrow)
+    {LibFunc_ZnwmRKSt9nothrow_t10hot_cold_t,      {MallocLike,       3, 0,  -1, -1, MallocFamily::CPPNew}},             // new(unsigned long, nothrow, hot_cold_t)
     {LibFunc_ZnwmSt11align_val_t,               {OpNewLike,        2,  0, -1,  1, MallocFamily::CPPNewAligned}},      // new(unsigned long, align_val_t)
+    {LibFunc_ZnwmSt11align_val_t10hot_cold_t,   {OpNewLike,        3, 0,  -1, 1, MallocFamily::CPPNewAligned}},       // new(unsigned long, align_val_t, hot_cold_t)
     {LibFunc_ZnwmSt11align_val_tRKSt9nothrow_t, {MallocLike,       3,  0, -1,  1, MallocFamily::CPPNewAligned}},      // new(unsigned long, align_val_t, nothrow)
+    {LibFunc_ZnwmSt11align_val_tRKSt9nothrow_t10hot_cold_t, {MallocLike,  4, 0,  -1, 1, MallocFamily::CPPNewAligned}},            // new(unsigned long, align_val_t, nothrow, hot_cold_t)
     {LibFunc_Znaj,                              {OpNewLike,        1,  0, -1, -1, MallocFamily::CPPNewArray}},        // new[](unsigned int)
     {LibFunc_ZnajRKSt9nothrow_t,                {MallocLike,       2,  0, -1, -1, MallocFamily::CPPNewArray}},        // new[](unsigned int, nothrow)
     {LibFunc_ZnajSt11align_val_t,               {OpNewLike,        2,  0, -1,  1, MallocFamily::CPPNewArrayAligned}}, // new[](unsigned int, align_val_t)
     {LibFunc_ZnajSt11align_val_tRKSt9nothrow_t, {MallocLike,       3,  0, -1,  1, MallocFamily::CPPNewArrayAligned}}, // new[](unsigned int, align_val_t, nothrow)
     {LibFunc_Znam,                              {OpNewLike,        1,  0, -1, -1, MallocFamily::CPPNewArray}},        // new[](unsigned long)
+    {LibFunc_Znam10hot_cold_t,                  {OpNewLike,        2, 0,  -1, -1, MallocFamily::CPPNew}},             // new[](unsigned long, hot_cold_t)
     {LibFunc_ZnamRKSt9nothrow_t,                {MallocLike,       2,  0, -1, -1, MallocFamily::CPPNewArray}},        // new[](unsigned long, nothrow)
+    {LibFunc_ZnamRKSt9nothrow_t10hot_cold_t,      {MallocLike,       3, 0,  -1, -1, MallocFamily::CPPNew}},             // new[](unsigned long, nothrow, hot_cold_t)
     {LibFunc_ZnamSt11align_val_t,               {OpNewLike,        2,  0, -1,  1, MallocFamily::CPPNewArrayAligned}}, // new[](unsigned long, align_val_t)
+    {LibFunc_ZnamSt11align_val_t10hot_cold_t,   {OpNewLike,        3, 0,  -1, 1, MallocFamily::CPPNewAligned}},       // new[](unsigned long, align_val_t, hot_cold_t)
     {LibFunc_ZnamSt11align_val_tRKSt9nothrow_t, {MallocLike,       3,  0, -1,  1, MallocFamily::CPPNewArrayAligned}}, // new[](unsigned long, align_val_t, nothrow)
+    {LibFunc_ZnamSt11align_val_tRKSt9nothrow_t10hot_cold_t, {MallocLike,  4, 0,  -1, 1, MallocFamily::CPPNewAligned}},            // new[](unsigned long, align_val_t, nothrow, hot_cold_t)
     {LibFunc_msvc_new_int,                      {OpNewLike,        1,  0, -1, -1, MallocFamily::MSVCNew}},            // new(unsigned int)
     {LibFunc_msvc_new_int_nothrow,              {MallocLike,       2,  0, -1, -1, MallocFamily::MSVCNew}},            // new(unsigned int, nothrow)
     {LibFunc_msvc_new_longlong,                 {OpNewLike,        1,  0, -1, -1, MallocFamily::MSVCNew}},            // new(unsigned long long)

diff  --git a/llvm/lib/Analysis/TargetLibraryInfo.cpp b/llvm/lib/Analysis/TargetLibraryInfo.cpp
index 666144158362f..00ed1edd3a881 100644
--- a/llvm/lib/Analysis/TargetLibraryInfo.cpp
+++ b/llvm/lib/Analysis/TargetLibraryInfo.cpp
@@ -474,6 +474,7 @@ static void initialize(TargetLibraryInfoImpl &TLI, const Triple &T,
     TLI.setUnavailable(LibFunc_ZnajSt11align_val_tRKSt9nothrow_t);
     TLI.setUnavailable(LibFunc_Znam);
     TLI.setUnavailable(LibFunc_ZnamRKSt9nothrow_t);
+    TLI.setUnavailable(LibFunc_ZnamRKSt9nothrow_t10hot_cold_t);
     TLI.setUnavailable(LibFunc_ZnamSt11align_val_t);
     TLI.setUnavailable(LibFunc_ZnamSt11align_val_tRKSt9nothrow_t);
     TLI.setUnavailable(LibFunc_Znwj);
@@ -482,8 +483,15 @@ static void initialize(TargetLibraryInfoImpl &TLI, const Triple &T,
     TLI.setUnavailable(LibFunc_ZnwjSt11align_val_tRKSt9nothrow_t);
     TLI.setUnavailable(LibFunc_Znwm);
     TLI.setUnavailable(LibFunc_ZnwmRKSt9nothrow_t);
+    TLI.setUnavailable(LibFunc_ZnwmRKSt9nothrow_t10hot_cold_t);
     TLI.setUnavailable(LibFunc_ZnwmSt11align_val_t);
     TLI.setUnavailable(LibFunc_ZnwmSt11align_val_tRKSt9nothrow_t);
+    TLI.setUnavailable(LibFunc_Znwm10hot_cold_t);
+    TLI.setUnavailable(LibFunc_ZnwmSt11align_val_t10hot_cold_t);
+    TLI.setUnavailable(LibFunc_ZnwmSt11align_val_tRKSt9nothrow_t10hot_cold_t);
+    TLI.setUnavailable(LibFunc_Znam10hot_cold_t);
+    TLI.setUnavailable(LibFunc_ZnamSt11align_val_t10hot_cold_t);
+    TLI.setUnavailable(LibFunc_ZnamSt11align_val_tRKSt9nothrow_t10hot_cold_t);
   } else {
     // Not MSVC, assume it's Itanium.
     TLI.setUnavailable(LibFunc_msvc_new_int);

diff  --git a/llvm/lib/Transforms/Utils/BuildLibCalls.cpp b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp
index 6adf2e639e01a..5de8ff84de771 100644
--- a/llvm/lib/Transforms/Utils/BuildLibCalls.cpp
+++ b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp
@@ -1941,3 +1941,87 @@ Value *llvm::emitCalloc(Value *Num, Value *Size, IRBuilderBase &B,
 
   return CI;
 }
+
+Value *llvm::emitHotColdNew(Value *Num, IRBuilderBase &B,
+                            const TargetLibraryInfo *TLI, LibFunc NewFunc,
+                            uint8_t HotCold) {
+  Module *M = B.GetInsertBlock()->getModule();
+  if (!isLibFuncEmittable(M, TLI, NewFunc))
+    return nullptr;
+
+  StringRef Name = TLI->getName(NewFunc);
+  FunctionCallee Func = M->getOrInsertFunction(Name, B.getInt8PtrTy(),
+                                               Num->getType(), B.getInt8Ty());
+  inferNonMandatoryLibFuncAttrs(M, Name, *TLI);
+  CallInst *CI = B.CreateCall(Func, {Num, B.getInt8(HotCold)}, Name);
+
+  if (const Function *F =
+          dyn_cast<Function>(Func.getCallee()->stripPointerCasts()))
+    CI->setCallingConv(F->getCallingConv());
+
+  return CI;
+}
+
+Value *llvm::emitHotColdNewNoThrow(Value *Num, Value *NoThrow, IRBuilderBase &B,
+                                   const TargetLibraryInfo *TLI,
+                                   LibFunc NewFunc, uint8_t HotCold) {
+  Module *M = B.GetInsertBlock()->getModule();
+  if (!isLibFuncEmittable(M, TLI, NewFunc))
+    return nullptr;
+
+  StringRef Name = TLI->getName(NewFunc);
+  FunctionCallee Func =
+      M->getOrInsertFunction(Name, B.getInt8PtrTy(), Num->getType(),
+                             NoThrow->getType(), B.getInt8Ty());
+  inferNonMandatoryLibFuncAttrs(M, Name, *TLI);
+  CallInst *CI = B.CreateCall(Func, {Num, NoThrow, B.getInt8(HotCold)}, Name);
+
+  if (const Function *F =
+          dyn_cast<Function>(Func.getCallee()->stripPointerCasts()))
+    CI->setCallingConv(F->getCallingConv());
+
+  return CI;
+}
+
+Value *llvm::emitHotColdNewAligned(Value *Num, Value *Align, IRBuilderBase &B,
+                                   const TargetLibraryInfo *TLI,
+                                   LibFunc NewFunc, uint8_t HotCold) {
+  Module *M = B.GetInsertBlock()->getModule();
+  if (!isLibFuncEmittable(M, TLI, NewFunc))
+    return nullptr;
+
+  StringRef Name = TLI->getName(NewFunc);
+  FunctionCallee Func = M->getOrInsertFunction(
+      Name, B.getInt8PtrTy(), Num->getType(), Align->getType(), B.getInt8Ty());
+  inferNonMandatoryLibFuncAttrs(M, Name, *TLI);
+  CallInst *CI = B.CreateCall(Func, {Num, Align, B.getInt8(HotCold)}, Name);
+
+  if (const Function *F =
+          dyn_cast<Function>(Func.getCallee()->stripPointerCasts()))
+    CI->setCallingConv(F->getCallingConv());
+
+  return CI;
+}
+
+Value *llvm::emitHotColdNewAlignedNoThrow(Value *Num, Value *Align,
+                                          Value *NoThrow, IRBuilderBase &B,
+                                          const TargetLibraryInfo *TLI,
+                                          LibFunc NewFunc, uint8_t HotCold) {
+  Module *M = B.GetInsertBlock()->getModule();
+  if (!isLibFuncEmittable(M, TLI, NewFunc))
+    return nullptr;
+
+  StringRef Name = TLI->getName(NewFunc);
+  FunctionCallee Func = M->getOrInsertFunction(
+      Name, B.getInt8PtrTy(), Num->getType(), Align->getType(),
+      NoThrow->getType(), B.getInt8Ty());
+  inferNonMandatoryLibFuncAttrs(M, Name, *TLI);
+  CallInst *CI =
+      B.CreateCall(Func, {Num, Align, NoThrow, B.getInt8(HotCold)}, Name);
+
+  if (const Function *F =
+          dyn_cast<Function>(Func.getCallee()->stripPointerCasts()))
+    CI->setCallingConv(F->getCallingConv());
+
+  return CI;
+}

diff  --git a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
index b6e5f84a30d8e..fff326c941fe4 100644
--- a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
@@ -44,6 +44,13 @@ static cl::opt<bool>
                          cl::desc("Enable unsafe double to float "
                                   "shrinking for math lib calls"));
 
+// Enable conversion of operator new calls with a MemProf hot or cold hint
+// to an operator new call that takes a hot/cold hint. Off by default since
+// not all allocators currently support this extension.
+static cl::opt<bool>
+    OptimizeHotColdNew("optimize-hot-cold-new", cl::Hidden, cl::init(false),
+                       cl::desc("Enable hot/cold operator new library calls"));
+
 //===----------------------------------------------------------------------===//
 // Helper Functions
 //===----------------------------------------------------------------------===//
@@ -1653,6 +1660,59 @@ Value *LibCallSimplifier::optimizeRealloc(CallInst *CI, IRBuilderBase &B) {
   return nullptr;
 }
 
+// When enabled, replace operator new() calls marked with a hot or cold memprof
+// attribute with an operator new() call that takes a hot_cold_t parameter.
+// Currently this is supported by the open source version of tcmalloc, see:
+// https://github.com/google/tcmalloc/blob/master/tcmalloc/new_extension.h
+Value *LibCallSimplifier::optimizeNew(CallInst *CI, IRBuilderBase &B,
+                                      LibFunc &Func) {
+  if (!OptimizeHotColdNew)
+    return nullptr;
+
+  uint8_t HotCold;
+  if (CI->getAttributes().getFnAttr("memprof").getValueAsString() == "cold")
+    HotCold = 0; // Coldest setting.
+  else if (CI->getAttributes().getFnAttr("memprof").getValueAsString() == "hot")
+    HotCold = 255; // Hottest setting.
+  else
+    return nullptr;
+
+  switch (Func) {
+  case LibFunc_Znwm:
+    return emitHotColdNew(CI->getArgOperand(0), B, TLI,
+                          LibFunc_Znwm10hot_cold_t, HotCold);
+  case LibFunc_Znam:
+    return emitHotColdNew(CI->getArgOperand(0), B, TLI,
+                          LibFunc_Znam10hot_cold_t, HotCold);
+  case LibFunc_ZnwmRKSt9nothrow_t:
+    return emitHotColdNewNoThrow(CI->getArgOperand(0), CI->getArgOperand(1), B,
+                                 TLI, LibFunc_ZnwmRKSt9nothrow_t10hot_cold_t,
+                                 HotCold);
+  case LibFunc_ZnamRKSt9nothrow_t:
+    return emitHotColdNewNoThrow(CI->getArgOperand(0), CI->getArgOperand(1), B,
+                                 TLI, LibFunc_ZnamRKSt9nothrow_t10hot_cold_t,
+                                 HotCold);
+  case LibFunc_ZnwmSt11align_val_t:
+    return emitHotColdNewAligned(CI->getArgOperand(0), CI->getArgOperand(1), B,
+                                 TLI, LibFunc_ZnwmSt11align_val_t10hot_cold_t,
+                                 HotCold);
+  case LibFunc_ZnamSt11align_val_t:
+    return emitHotColdNewAligned(CI->getArgOperand(0), CI->getArgOperand(1), B,
+                                 TLI, LibFunc_ZnamSt11align_val_t10hot_cold_t,
+                                 HotCold);
+  case LibFunc_ZnwmSt11align_val_tRKSt9nothrow_t:
+    return emitHotColdNewAlignedNoThrow(
+        CI->getArgOperand(0), CI->getArgOperand(1), CI->getArgOperand(2), B,
+        TLI, LibFunc_ZnwmSt11align_val_tRKSt9nothrow_t10hot_cold_t, HotCold);
+  case LibFunc_ZnamSt11align_val_tRKSt9nothrow_t:
+    return emitHotColdNewAlignedNoThrow(
+        CI->getArgOperand(0), CI->getArgOperand(1), CI->getArgOperand(2), B,
+        TLI, LibFunc_ZnamSt11align_val_tRKSt9nothrow_t10hot_cold_t, HotCold);
+  default:
+    assert(false);
+  }
+}
+
 //===----------------------------------------------------------------------===//
 // Math Library Optimizations
 //===----------------------------------------------------------------------===//
@@ -3448,6 +3508,15 @@ Value *LibCallSimplifier::optimizeStringMemoryLibCall(CallInst *CI,
       return optimizeWcslen(CI, Builder);
     case LibFunc_bcopy:
       return optimizeBCopy(CI, Builder);
+    case LibFunc_Znwm:
+    case LibFunc_ZnwmRKSt9nothrow_t:
+    case LibFunc_ZnwmSt11align_val_t:
+    case LibFunc_ZnwmSt11align_val_tRKSt9nothrow_t:
+    case LibFunc_Znam:
+    case LibFunc_ZnamRKSt9nothrow_t:
+    case LibFunc_ZnamSt11align_val_t:
+    case LibFunc_ZnamSt11align_val_tRKSt9nothrow_t:
+      return optimizeNew(CI, Builder, Func);
     default:
       break;
     }

diff  --git a/llvm/test/Transforms/InstCombine/simplify-libcalls-new.ll b/llvm/test/Transforms/InstCombine/simplify-libcalls-new.ll
new file mode 100644
index 0000000000000..47917fd5434e7
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/simplify-libcalls-new.ll
@@ -0,0 +1,182 @@
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s --implicit-check-not=hot_cold_t
+; RUN: opt < %s -passes=instcombine -optimize-hot-cold-new -S | FileCheck %s --check-prefix=HOTCOLD
+
+;; Check that operator new(unsigned long) converted to
+;; operator new(unsigned long, hot_cold_t) with a hot or cold attribute.
+; HOTCOLD-LABEL: @new()
+define void @new() {
+  ;; Attribute cold converted to hot_cold_t value 0 (coldest).
+  ; HOTCOLD: @_Znwm10hot_cold_t(i64 10, i8 0)
+  %call = call ptr @_Znwm(i64 10) #0
+  call void @dummy(ptr %call)
+  ;; Attribute notcold has no effect.
+  ; HOTCOLD: @_Znwm(i64 10)
+  %call1 = call ptr @_Znwm(i64 10) #1
+  call void @dummy(ptr %call1)
+  ;; Attribute hot converted to hot_cold_t value 255 (-1) (hottest).
+  ; HOTCOLD: @_Znwm10hot_cold_t(i64 10, i8 -1)
+  %call2 = call ptr @_Znwm(i64 10) #2
+  call void @dummy(ptr %call2)
+  ret void
+}
+
+;; Check that operator new(unsigned long, std::align_val_t) converted to
+;; operator new(unsigned long, std::align_val_t, hot_cold_t) with a hot or
+;; cold attribute.
+; HOTCOLD-LABEL: @new_align()
+define void @new_align() {
+  ;; Attribute cold converted to hot_cold_t value 0 (coldest).
+  ; HOTCOLD: @_ZnwmSt11align_val_t10hot_cold_t(i64 10, i64 8, i8 0)
+  %call = call ptr @_ZnwmSt11align_val_t(i64 10, i64 8) #0
+  call void @dummy(ptr %call)
+  ;; Attribute notcold has no effect.
+  ; HOTCOLD: @_ZnwmSt11align_val_t(i64 10, i64 8)
+  %call1 = call ptr @_ZnwmSt11align_val_t(i64 10, i64 8) #1
+  call void @dummy(ptr %call1)
+  ;; Attribute hot converted to hot_cold_t value 255 (-1) (hottest).
+  ; HOTCOLD: @_ZnwmSt11align_val_t10hot_cold_t(i64 10, i64 8, i8 -1)
+  %call2 = call ptr @_ZnwmSt11align_val_t(i64 10, i64 8) #2
+  call void @dummy(ptr %call2)
+  ret void
+}
+
+;; Check that operator new(unsigned long, const std::nothrow_t&) converted to
+;; operator new(unsigned long, const std::nothrow_t&, hot_cold_t) with a hot or
+;; cold attribute.
+; HOTCOLD-LABEL: @new_nothrow()
+define void @new_nothrow() {
+  %nt = alloca i8
+  ;; Attribute cold converted to hot_cold_t value 0 (coldest).
+  ; HOTCOLD: @_ZnwmRKSt9nothrow_t10hot_cold_t(i64 10, ptr nonnull %nt, i8 0)
+  %call = call ptr @_ZnwmRKSt9nothrow_t(i64 10, ptr %nt) #0
+  call void @dummy(ptr %call)
+  ;; Attribute notcold has no effect.
+  ; HOTCOLD: @_ZnwmRKSt9nothrow_t(i64 10, ptr nonnull %nt)
+  %call1 = call ptr @_ZnwmRKSt9nothrow_t(i64 10, ptr %nt) #1
+  call void @dummy(ptr %call1)
+  ;; Attribute hot converted to hot_cold_t value 255 (-1) (hottest).
+  ; HOTCOLD: @_ZnwmRKSt9nothrow_t10hot_cold_t(i64 10, ptr nonnull %nt, i8 -1)
+  %call2 = call ptr @_ZnwmRKSt9nothrow_t(i64 10, ptr %nt) #2
+  call void @dummy(ptr %call2)
+  ret void
+}
+
+;; Check that operator new(unsigned long, std::align_val_t, const std::nothrow_t&)
+;; converted to
+;; operator new(unsigned long, std::align_val_t, const std::nothrow_t&, hot_cold_t)
+;; with a hot or cold attribute.
+; HOTCOLD-LABEL: @new_align_nothrow()
+define void @new_align_nothrow() {
+  %nt = alloca i8
+  ;; Attribute cold converted to hot_cold_t value 0 (coldest).
+  ; HOTCOLD: @_ZnwmSt11align_val_tRKSt9nothrow_t10hot_cold_t(i64 10, i64 8, ptr nonnull %nt, i8 0)
+  %call = call ptr @_ZnwmSt11align_val_tRKSt9nothrow_t(i64 10, i64 8, ptr %nt) #0
+  call void @dummy(ptr %call)
+  ;; Attribute notcold has no effect.
+  ; HOTCOLD: @_ZnwmSt11align_val_tRKSt9nothrow_t(i64 10, i64 8, ptr nonnull %nt)
+  %call1 = call ptr @_ZnwmSt11align_val_tRKSt9nothrow_t(i64 10, i64 8, ptr %nt) #1
+  call void @dummy(ptr %call1)
+  ;; Attribute hot converted to hot_cold_t value 255 (-1) (hottest).
+  ; HOTCOLD: @_ZnwmSt11align_val_tRKSt9nothrow_t10hot_cold_t(i64 10, i64 8, ptr nonnull %nt, i8 -1)
+  %call2 = call ptr @_ZnwmSt11align_val_tRKSt9nothrow_t(i64 10, i64 8, ptr %nt) #2
+  call void @dummy(ptr %call2)
+  ret void
+}
+
+;; Check that operator new[](unsigned long) converted to
+;; operator new[](unsigned long, hot_cold_t) with a hot or cold attribute.
+; HOTCOLD-LABEL: @array_new()
+define void @array_new() {
+  ;; Attribute cold converted to hot_cold_t value 0 (coldest).
+  ; HOTCOLD: @_Znam10hot_cold_t(i64 10, i8 0)
+  %call = call ptr @_Znam(i64 10) #0
+  call void @dummy(ptr %call)
+  ;; Attribute notcold has no effect.
+  ; HOTCOLD: @_Znam(i64 10)
+  %call1 = call ptr @_Znam(i64 10) #1
+  call void @dummy(ptr %call1)
+  ;; Attribute hot converted to hot_cold_t value 255 (-1) (hottest).
+  ; HOTCOLD: @_Znam10hot_cold_t(i64 10, i8 -1)
+  %call2 = call ptr @_Znam(i64 10) #2
+  call void @dummy(ptr %call2)
+  ret void
+}
+
+;; Check that operator new[](unsigned long, std::align_val_t) converted to
+;; operator new[](unsigned long, std::align_val_t, hot_cold_t) with a hot or
+;; cold attribute.
+; HOTCOLD-LABEL: @array_new_align()
+define void @array_new_align() {
+  ;; Attribute cold converted to hot_cold_t value 0 (coldest).
+  ; HOTCOLD: @_ZnamSt11align_val_t10hot_cold_t(i64 10, i64 8, i8 0)
+  %call = call ptr @_ZnamSt11align_val_t(i64 10, i64 8) #0
+  call void @dummy(ptr %call)
+  ;; Attribute notcold has no effect.
+  ; HOTCOLD: @_ZnamSt11align_val_t(i64 10, i64 8)
+  %call1 = call ptr @_ZnamSt11align_val_t(i64 10, i64 8) #1
+  call void @dummy(ptr %call1)
+  ;; Attribute hot converted to hot_cold_t value 255 (-1) (hottest).
+  ; HOTCOLD: @_ZnamSt11align_val_t10hot_cold_t(i64 10, i64 8, i8 -1)
+  %call2 = call ptr @_ZnamSt11align_val_t(i64 10, i64 8) #2
+  call void @dummy(ptr %call2)
+  ret void
+}
+
+;; Check that operator new[](unsigned long, const std::nothrow_t&) converted to
+;; operator new[](unsigned long, const std::nothrow_t&, hot_cold_t) with a hot or
+;; cold attribute.
+; HOTCOLD-LABEL: @array_new_nothrow()
+define void @array_new_nothrow() {
+  %nt = alloca i8
+  ;; Attribute cold converted to hot_cold_t value 0 (coldest).
+  ; HOTCOLD: @_ZnamRKSt9nothrow_t10hot_cold_t(i64 10, ptr nonnull %nt, i8 0)
+  %call = call ptr @_ZnamRKSt9nothrow_t(i64 10, ptr %nt) #0
+  call void @dummy(ptr %call)
+  ;; Attribute notcold has no effect.
+  ; HOTCOLD: @_ZnamRKSt9nothrow_t(i64 10, ptr nonnull %nt)
+  %call1 = call ptr @_ZnamRKSt9nothrow_t(i64 10, ptr %nt) #1
+  call void @dummy(ptr %call1)
+  ;; Attribute hot converted to hot_cold_t value 255 (-1) (hottest).
+  ; HOTCOLD: @_ZnamRKSt9nothrow_t10hot_cold_t(i64 10, ptr nonnull %nt, i8 -1)
+  %call2 = call ptr @_ZnamRKSt9nothrow_t(i64 10, ptr %nt) #2
+  call void @dummy(ptr %call2)
+  ret void
+}
+
+;; Check that operator new[](unsigned long, std::align_val_t, const std::nothrow_t&)
+;; converted to
+;; operator new[](unsigned long, std::align_val_t, const std::nothrow_t&, hot_cold_t)
+;; with a hot or cold attribute.
+; HOTCOLD-LABEL: @array_new_align_nothrow()
+define void @array_new_align_nothrow() {
+  %nt = alloca i8
+  ;; Attribute cold converted to hot_cold_t value 0 (coldest).
+  ; HOTCOLD: @_ZnamSt11align_val_tRKSt9nothrow_t10hot_cold_t(i64 10, i64 8, ptr nonnull %nt, i8 0)
+  %call = call ptr @_ZnamSt11align_val_tRKSt9nothrow_t(i64 10, i64 8, ptr %nt) #0
+  call void @dummy(ptr %call)
+  ;; Attribute notcold has no effect.
+  ; HOTCOLD: @_ZnamSt11align_val_tRKSt9nothrow_t(i64 10, i64 8, ptr nonnull %nt)
+  %call1 = call ptr @_ZnamSt11align_val_tRKSt9nothrow_t(i64 10, i64 8, ptr %nt) #1
+  call void @dummy(ptr %call1)
+  ;; Attribute hot converted to hot_cold_t value 255 (-1) (hottest).
+  ; HOTCOLD: @_ZnamSt11align_val_tRKSt9nothrow_t10hot_cold_t(i64 10, i64 8, ptr nonnull %nt, i8 -1)
+  %call2 = call ptr @_ZnamSt11align_val_tRKSt9nothrow_t(i64 10, i64 8, ptr %nt) #2
+  call void @dummy(ptr %call2)
+  ret void
+}
+
+;; So that instcombine doesn't optimize out the call.
+declare void @dummy(ptr)
+
+declare ptr @_Znwm(i64)
+declare ptr @_ZnwmSt11align_val_t(i64, i64)
+declare ptr @_ZnwmRKSt9nothrow_t(i64, ptr)
+declare ptr @_ZnwmSt11align_val_tRKSt9nothrow_t(i64, i64, ptr)
+declare ptr @_Znam(i64)
+declare ptr @_ZnamSt11align_val_t(i64, i64)
+declare ptr @_ZnamRKSt9nothrow_t(i64, ptr)
+declare ptr @_ZnamSt11align_val_tRKSt9nothrow_t(i64, i64, ptr)
+
+attributes #0 = { builtin allocsize(0) "memprof"="cold" }
+attributes #1 = { builtin allocsize(0) "memprof"="notcold" }
+attributes #2 = { builtin allocsize(0) "memprof"="hot" }

diff  --git a/llvm/test/tools/llvm-tli-checker/ps4-tli-check.yaml b/llvm/test/tools/llvm-tli-checker/ps4-tli-check.yaml
index 06e3794ded09e..b1d4c1303dc7d 100644
--- a/llvm/test/tools/llvm-tli-checker/ps4-tli-check.yaml
+++ b/llvm/test/tools/llvm-tli-checker/ps4-tli-check.yaml
@@ -32,13 +32,14 @@
 # RUN: FileCheck %s --check-prefix=AVAIL --input-file %t3.txt
 # RUN: FileCheck %s --check-prefix=UNAVAIL --input-file %t3.txt
 #
-# CHECK: << Total TLI yes SDK no:  0
+# CHECK: << Total TLI yes SDK no:  8
 # CHECK: >> Total TLI no  SDK yes: 0
 # CHECK: == Total TLI yes SDK yes: 235
 #
 # WRONG_DETAIL: << TLI yes SDK no : '_ZdaPv' aka operator delete[](void*)
 # WRONG_DETAIL: >> TLI no  SDK yes: '_ZdaPvj' aka operator delete[](void*, unsigned int)
-# WRONG_SUMMARY: << Total TLI yes SDK no:  1{{$}}
+# WRONG_DETAIL-COUNT-8: << TLI yes SDK no : {{.*}}hot_cold_t
+# WRONG_SUMMARY: << Total TLI yes SDK no:  9{{$}}
 # WRONG_SUMMARY: >> Total TLI no  SDK yes: 1{{$}}
 # WRONG_SUMMARY: == Total TLI yes SDK yes: 234
 #
@@ -46,8 +47,8 @@
 ## the exact count first; the two directives should add up to that.
 ## Yes, this means additions to TLI will fail this test, but the argument
 ## to -COUNT can't be an expression.
-# AVAIL: TLI knows 468 symbols, 235 available
-# AVAIL-COUNT-235: {{^}} available
+# AVAIL: TLI knows 476 symbols, 243 available
+# AVAIL-COUNT-243: {{^}} available
 # AVAIL-NOT:       {{^}} available
 # UNAVAIL-COUNT-233: not available
 # UNAVAIL-NOT:       not available

diff  --git a/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp b/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp
index 261786b304611..5c47dca605364 100644
--- a/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp
+++ b/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp
@@ -433,17 +433,27 @@ TEST_F(TargetLibraryInfoTest, ValidProto) {
       "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* @_Znam10hot_cold_t(i64, i8)\n"
       "declare i8* @_ZnamRKSt9nothrow_t(i64, %struct*)\n"
+      "declare i8* @_ZnamRKSt9nothrow_t10hot_cold_t(i64, %struct*, i8)\n"
       "declare i8* @_ZnamSt11align_val_t(i64, i64)\n"
+      "declare i8* @_ZnamSt11align_val_t10hot_cold_t(i64, i64, i8)\n"
       "declare i8* @_ZnamSt11align_val_tRKSt9nothrow_t(i64, i64, %struct*)\n"
+      "declare i8* @_ZnamSt11align_val_tRKSt9nothrow_t10hot_cold_t(i64, i64, "
+      "%struct*, i8)\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* @_Znwm10hot_cold_t(i64, i8)\n"
       "declare i8* @_ZnwmRKSt9nothrow_t(i64, %struct*)\n"
+      "declare i8* @_ZnwmRKSt9nothrow_t10hot_cold_t(i64, %struct*, i8)\n"
       "declare i8* @_ZnwmSt11align_val_t(i64, i64)\n"
+      "declare i8* @_ZnwmSt11align_val_t10hot_cold_t(i64, i64, i8)\n"
       "declare i8* @_ZnwmSt11align_val_tRKSt9nothrow_t(i64, i64, %struct*)\n"
+      "declare i8* @_ZnwmSt11align_val_tRKSt9nothrow_t10hot_cold_t(i64, i64, "
+      "%struct*, i8)\n"
 
       "declare void @\"??3 at YAXPEAX@Z\"(i8*)\n"
       "declare void @\"??3 at YAXPEAXAEBUnothrow_t@std@@@Z\"(i8*, %struct*)\n"


        


More information about the llvm-commits mailing list