[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
diff --git a/llvm/include/llvm/Analysis/TargetLibraryInfo.def b/llvm/include/llvm/Analysis/TargetLibraryInfo.def
index 5f6af35..72a32a5 100644
--- a/llvm/include/llvm/Analysis/TargetLibraryInfo.def
+++ b/llvm/include/llvm/Analysis/TargetLibraryInfo.def
@@ -256,21 +256,46 @@
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_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 bb1cb07..429970c 100644
--- a/llvm/include/llvm/Transforms/Utils/BuildLibCalls.h
+++ b/llvm/include/llvm/Transforms/Utils/BuildLibCalls.h
@@ -248,6 +248,21 @@
/// 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 11c9717..9269216 100644
--- a/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h
+++ b/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h
@@ -181,6 +181,7 @@
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 4d818bb..116a922 100644
--- a/llvm/lib/Analysis/MemoryBuiltins.cpp
+++ b/llvm/lib/Analysis/MemoryBuiltins.cpp
@@ -115,17 +115,25 @@
{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 6661441..00ed1ed 100644
--- a/llvm/lib/Analysis/TargetLibraryInfo.cpp
+++ b/llvm/lib/Analysis/TargetLibraryInfo.cpp
@@ -474,6 +474,7 @@
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 @@
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 6adf2e6..5de8ff8 100644
--- a/llvm/lib/Transforms/Utils/BuildLibCalls.cpp
+++ b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp
@@ -1941,3 +1941,87 @@
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 b6e5f84..fff326c 100644
--- a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
@@ -44,6 +44,13 @@
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 @@
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 @@
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 0000000..47917fd
--- /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 06e3794..b1d4c13 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 261786b..5c47dca 100644
--- a/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp
+++ b/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp
@@ -433,17 +433,27 @@
"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@YAXPEAX@Z\"(i8*)\n"
"declare void @\"??3@YAXPEAXAEBUnothrow_t@std@@@Z\"(i8*, %struct*)\n"