diff --git a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp --- a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -51,6 +51,38 @@ OptimizeHotColdNew("optimize-hot-cold-new", cl::Hidden, cl::init(false), cl::desc("Enable hot/cold operator new library calls")); +namespace { + +// Specialized parser to ensure the hint is an 8 bit value (we can't specify +// uint8_t to opt<> as that is interpreted to mean that we are passing a char +// option with a specific set of values. +struct HotColdHintParser : public cl::parser { + HotColdHintParser(cl::Option &O) : cl::parser(O) {} + + bool parse(cl::Option &O, StringRef ArgName, StringRef Arg, unsigned &Value) { + if (Arg.getAsInteger(0, Value)) + return O.error("'" + Arg + "' value invalid for uint argument!"); + + if (Value > 255) + return O.error("'" + Arg + "' value must be in the range [0, 255]!"); + + return false; + } +}; + +} // end anonymous namespace + +// Hot/cold operator new takes an 8 bit hotness hint, where 0 is the coldest +// and 255 is the hottest. Default to 1 value away from the coldest and hottest +// hints, so that the compiler hinted allocations are slightly less strong than +// manually inserted hints at the two extremes. +static cl::opt ColdNewHintValue( + "cold-new-hint-value", cl::Hidden, cl::init(1), + cl::desc("Value to pass to hot/cold operator new for cold allocation")); +static cl::opt HotNewHintValue( + "hot-new-hint-value", cl::Hidden, cl::init(254), + cl::desc("Value to pass to hot/cold operator new for hot allocation")); + //===----------------------------------------------------------------------===// // Helper Functions //===----------------------------------------------------------------------===// @@ -1701,9 +1733,9 @@ uint8_t HotCold; if (CI->getAttributes().getFnAttr("memprof").getValueAsString() == "cold") - HotCold = 0; // Coldest setting. + HotCold = ColdNewHintValue; else if (CI->getAttributes().getFnAttr("memprof").getValueAsString() == "hot") - HotCold = 255; // Hottest setting. + HotCold = HotNewHintValue; else return nullptr; diff --git a/llvm/test/Transforms/InstCombine/simplify-libcalls-new.ll b/llvm/test/Transforms/InstCombine/simplify-libcalls-new.ll --- a/llvm/test/Transforms/InstCombine/simplify-libcalls-new.ll +++ b/llvm/test/Transforms/InstCombine/simplify-libcalls-new.ll @@ -1,20 +1,33 @@ +;; Test behavior of -optimize-hot-cold-new and related options. + +;; Check that we don't get hot/cold new calls without enabling it explicitly. ; 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 + +;; First check with the default cold and hot hint values (255 = -2). +; RUN: opt < %s -passes=instcombine -optimize-hot-cold-new -S | FileCheck %s --check-prefix=HOTCOLD -DCOLD=1 -DHOT=-2 + +;; Next check with the non-default cold and hot hint values (200 =-56). +; RUN: opt < %s -passes=instcombine -optimize-hot-cold-new -cold-new-hint-value=5 -hot-new-hint-value=200 -S | FileCheck %s --check-prefix=HOTCOLD -DCOLD=5 -DHOT=-56 + +;; Make sure that values not in 0..255 are flagged with an error +; RUN: not opt < %s -passes=instcombine -optimize-hot-cold-new -cold-new-hint-value=256 -S 2>&1 | FileCheck %s --check-prefix=ERROR +; RUN: not opt < %s -passes=instcombine -optimize-hot-cold-new -hot-new-hint-value=5000 -S 2>&1 | FileCheck %s --check-prefix=ERROR +; ERROR: value must be in the range [0, 255]! ;; 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: @_Znwm12__hot_cold_t(i64 10, i8 0) + ;; Attribute cold converted to __hot_cold_t cold value. + ; HOTCOLD: @_Znwm12__hot_cold_t(i64 10, i8 [[COLD]]) %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: @_Znwm12__hot_cold_t(i64 10, i8 -1) + ;; Attribute hot converted to __hot_cold_t hot value. + ; HOTCOLD: @_Znwm12__hot_cold_t(i64 10, i8 [[HOT]]) %call2 = call ptr @_Znwm(i64 10) #2 call void @dummy(ptr %call2) ret void @@ -25,16 +38,16 @@ ;; cold attribute. ; HOTCOLD-LABEL: @new_align() define void @new_align() { - ;; Attribute cold converted to __hot_cold_t value 0 (coldest). - ; HOTCOLD: @_ZnwmSt11align_val_t12__hot_cold_t(i64 10, i64 8, i8 0) + ;; Attribute cold converted to __hot_cold_t cold value. + ; HOTCOLD: @_ZnwmSt11align_val_t12__hot_cold_t(i64 10, i64 8, i8 [[COLD]]) %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_t12__hot_cold_t(i64 10, i64 8, i8 -1) + ;; Attribute hot converted to __hot_cold_t hot value. + ; HOTCOLD: @_ZnwmSt11align_val_t12__hot_cold_t(i64 10, i64 8, i8 [[HOT]]) %call2 = call ptr @_ZnwmSt11align_val_t(i64 10, i64 8) #2 call void @dummy(ptr %call2) ret void @@ -46,16 +59,16 @@ ; HOTCOLD-LABEL: @new_nothrow() define void @new_nothrow() { %nt = alloca i8 - ;; Attribute cold converted to __hot_cold_t value 0 (coldest). - ; HOTCOLD: @_ZnwmRKSt9nothrow_t12__hot_cold_t(i64 10, ptr nonnull %nt, i8 0) + ;; Attribute cold converted to __hot_cold_t cold value. + ; HOTCOLD: @_ZnwmRKSt9nothrow_t12__hot_cold_t(i64 10, ptr nonnull %nt, i8 [[COLD]]) %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_t12__hot_cold_t(i64 10, ptr nonnull %nt, i8 -1) + ;; Attribute hot converted to __hot_cold_t hot value. + ; HOTCOLD: @_ZnwmRKSt9nothrow_t12__hot_cold_t(i64 10, ptr nonnull %nt, i8 [[HOT]]) %call2 = call ptr @_ZnwmRKSt9nothrow_t(i64 10, ptr %nt) #2 call void @dummy(ptr %call2) ret void @@ -68,16 +81,16 @@ ; 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_t12__hot_cold_t(i64 10, i64 8, ptr nonnull %nt, i8 0) + ;; Attribute cold converted to __hot_cold_t cold value. + ; HOTCOLD: @_ZnwmSt11align_val_tRKSt9nothrow_t12__hot_cold_t(i64 10, i64 8, ptr nonnull %nt, i8 [[COLD]]) %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_t12__hot_cold_t(i64 10, i64 8, ptr nonnull %nt, i8 -1) + ;; Attribute hot converted to __hot_cold_t hot value. + ; HOTCOLD: @_ZnwmSt11align_val_tRKSt9nothrow_t12__hot_cold_t(i64 10, i64 8, ptr nonnull %nt, i8 [[HOT]]) %call2 = call ptr @_ZnwmSt11align_val_tRKSt9nothrow_t(i64 10, i64 8, ptr %nt) #2 call void @dummy(ptr %call2) ret void @@ -87,16 +100,16 @@ ;; 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: @_Znam12__hot_cold_t(i64 10, i8 0) + ;; Attribute cold converted to __hot_cold_t cold value. + ; HOTCOLD: @_Znam12__hot_cold_t(i64 10, i8 [[COLD]]) %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: @_Znam12__hot_cold_t(i64 10, i8 -1) + ;; Attribute hot converted to __hot_cold_t hot value. + ; HOTCOLD: @_Znam12__hot_cold_t(i64 10, i8 [[HOT]]) %call2 = call ptr @_Znam(i64 10) #2 call void @dummy(ptr %call2) ret void @@ -107,16 +120,16 @@ ;; 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_t12__hot_cold_t(i64 10, i64 8, i8 0) + ;; Attribute cold converted to __hot_cold_t cold value. + ; HOTCOLD: @_ZnamSt11align_val_t12__hot_cold_t(i64 10, i64 8, i8 [[COLD]]) %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_t12__hot_cold_t(i64 10, i64 8, i8 -1) + ;; Attribute hot converted to __hot_cold_t hot value. + ; HOTCOLD: @_ZnamSt11align_val_t12__hot_cold_t(i64 10, i64 8, i8 [[HOT]]) %call2 = call ptr @_ZnamSt11align_val_t(i64 10, i64 8) #2 call void @dummy(ptr %call2) ret void @@ -128,16 +141,16 @@ ; 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_t12__hot_cold_t(i64 10, ptr nonnull %nt, i8 0) + ;; Attribute cold converted to __hot_cold_t cold value. + ; HOTCOLD: @_ZnamRKSt9nothrow_t12__hot_cold_t(i64 10, ptr nonnull %nt, i8 [[COLD]]) %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_t12__hot_cold_t(i64 10, ptr nonnull %nt, i8 -1) + ;; Attribute hot converted to __hot_cold_t hot value. + ; HOTCOLD: @_ZnamRKSt9nothrow_t12__hot_cold_t(i64 10, ptr nonnull %nt, i8 [[HOT]]) %call2 = call ptr @_ZnamRKSt9nothrow_t(i64 10, ptr %nt) #2 call void @dummy(ptr %call2) ret void @@ -150,16 +163,16 @@ ; 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_t12__hot_cold_t(i64 10, i64 8, ptr nonnull %nt, i8 0) + ;; Attribute cold converted to __hot_cold_t cold value. + ; HOTCOLD: @_ZnamSt11align_val_tRKSt9nothrow_t12__hot_cold_t(i64 10, i64 8, ptr nonnull %nt, i8 [[COLD]]) %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_t12__hot_cold_t(i64 10, i64 8, ptr nonnull %nt, i8 -1) + ;; Attribute hot converted to __hot_cold_t hot value. + ; HOTCOLD: @_ZnamSt11align_val_tRKSt9nothrow_t12__hot_cold_t(i64 10, i64 8, ptr nonnull %nt, i8 [[HOT]]) %call2 = call ptr @_ZnamSt11align_val_tRKSt9nothrow_t(i64 10, i64 8, ptr %nt) #2 call void @dummy(ptr %call2) ret void