Skip to content

Commit ad4594e

Browse files
[MemProf] Allow hint update on existing calls to nobuiltin hot/cold new (#156476)
Explicit calls to ::operator new are marked nobuiltin and cannot be elided or updated as they may call user defined versions. However, existing calls to the hot/cold versions of new only need their hint parameter value updated, which does not mutate the call.
1 parent 96c2776 commit ad4594e

File tree

3 files changed

+123
-2
lines changed

3 files changed

+123
-2
lines changed

llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ class LibCallSimplifier {
189189
Value *optimizeMemSet(CallInst *CI, IRBuilderBase &B);
190190
Value *optimizeRealloc(CallInst *CI, IRBuilderBase &B);
191191
Value *optimizeNew(CallInst *CI, IRBuilderBase &B, LibFunc &Func);
192+
Value *optimizeExistingHotColdNew(CallInst *CI, IRBuilderBase &B);
192193
Value *optimizeWcslen(CallInst *CI, IRBuilderBase &B);
193194
Value *optimizeBCopy(CallInst *CI, IRBuilderBase &B);
194195

llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1719,6 +1719,37 @@ Value *LibCallSimplifier::optimizeRealloc(CallInst *CI, IRBuilderBase &B) {
17191719
return nullptr;
17201720
}
17211721

1722+
// Allow existing calls to operator new() that takes a __hot_cold_t parameter to
1723+
// be updated with a compiler-determined hot cold hint value. This is used in
1724+
// cases where the call is marked nobuiltin (because operator new called
1725+
// explicitly) and therefore cannot be replaced with a different callee.
1726+
Value *LibCallSimplifier::optimizeExistingHotColdNew(CallInst *CI,
1727+
IRBuilderBase &B) {
1728+
if (!OptimizeHotColdNew || !OptimizeExistingHotColdNew)
1729+
return nullptr;
1730+
Function *Callee = CI->getCalledFunction();
1731+
if (!Callee)
1732+
return nullptr;
1733+
LibFunc Func;
1734+
if (!TLI->getLibFunc(*Callee, Func))
1735+
return nullptr;
1736+
switch (Func) {
1737+
case LibFunc_Znwm12__hot_cold_t:
1738+
case LibFunc_ZnwmRKSt9nothrow_t12__hot_cold_t:
1739+
case LibFunc_ZnwmSt11align_val_t12__hot_cold_t:
1740+
case LibFunc_ZnwmSt11align_val_tRKSt9nothrow_t12__hot_cold_t:
1741+
case LibFunc_Znam12__hot_cold_t:
1742+
case LibFunc_ZnamRKSt9nothrow_t12__hot_cold_t:
1743+
case LibFunc_ZnamSt11align_val_t12__hot_cold_t:
1744+
case LibFunc_ZnamSt11align_val_tRKSt9nothrow_t12__hot_cold_t:
1745+
case LibFunc_size_returning_new_hot_cold:
1746+
case LibFunc_size_returning_new_aligned_hot_cold:
1747+
return optimizeNew(CI, B, Func);
1748+
default:
1749+
return nullptr;
1750+
}
1751+
}
1752+
17221753
// When enabled, replace operator new() calls marked with a hot or cold memprof
17231754
// attribute with an operator new() call that takes a __hot_cold_t parameter.
17241755
// Currently this is supported by the open source version of tcmalloc, see:
@@ -4094,8 +4125,11 @@ Value *LibCallSimplifier::optimizeCall(CallInst *CI, IRBuilderBase &Builder) {
40944125
// TODO: Split out the code below that operates on FP calls so that
40954126
// we can all non-FP calls with the StrictFP attribute to be
40964127
// optimized.
4097-
if (CI->isNoBuiltin())
4098-
return nullptr;
4128+
if (CI->isNoBuiltin()) {
4129+
// If this is an existing call to a hot cold operator new, we can update the
4130+
// hint parameter value, which doesn't change the callee.
4131+
return optimizeExistingHotColdNew(CI, Builder);
4132+
}
40994133

41004134
LibFunc Func;
41014135
Function *Callee = CI->getCalledFunction();

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

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ define void @new() {
3636
; HOTCOLD: @_Znwm12__hot_cold_t(i64 10, i8 [[HOT]])
3737
%call2 = call ptr @_Znwm(i64 10) #2
3838
call void @dummy(ptr %call2)
39+
;; Attribute cold on a nobuiltin call has no effect.
40+
; HOTCOLD: @_Znwm(i64 10)
41+
%call3 = call ptr @_Znwm(i64 10) #6
42+
call void @dummy(ptr %call3)
3943
ret void
4044
}
4145

@@ -56,6 +60,10 @@ define void @new_align() {
5660
; HOTCOLD: @_ZnwmSt11align_val_t12__hot_cold_t(i64 10, i64 8, i8 [[HOT]])
5761
%call2 = call ptr @_ZnwmSt11align_val_t(i64 10, i64 8) #2
5862
call void @dummy(ptr %call2)
63+
;; Attribute cold on a nobuiltin call has no effect.
64+
; HOTCOLD: @_ZnwmSt11align_val_t(i64 10, i64 8)
65+
%call3 = call ptr @_ZnwmSt11align_val_t(i64 10, i64 8) #6
66+
call void @dummy(ptr %call3)
5967
ret void
6068
}
6169

@@ -77,6 +85,10 @@ define void @new_nothrow() {
7785
; HOTCOLD: @_ZnwmRKSt9nothrow_t12__hot_cold_t(i64 10, ptr nonnull %nt, i8 [[HOT]])
7886
%call2 = call ptr @_ZnwmRKSt9nothrow_t(i64 10, ptr %nt) #2
7987
call void @dummy(ptr %call2)
88+
;; Attribute cold on a nobuiltin call has no effect.
89+
; HOTCOLD: @_ZnwmRKSt9nothrow_t(i64 10, ptr nonnull %nt)
90+
%call3 = call ptr @_ZnwmRKSt9nothrow_t(i64 10, ptr %nt) #6
91+
call void @dummy(ptr %call3)
8092
ret void
8193
}
8294

@@ -99,6 +111,10 @@ define void @new_align_nothrow() {
99111
; HOTCOLD: @_ZnwmSt11align_val_tRKSt9nothrow_t12__hot_cold_t(i64 10, i64 8, ptr nonnull %nt, i8 [[HOT]])
100112
%call2 = call ptr @_ZnwmSt11align_val_tRKSt9nothrow_t(i64 10, i64 8, ptr %nt) #2
101113
call void @dummy(ptr %call2)
114+
;; Attribute cold on a nobuiltin call has no effect.
115+
; HOTCOLD: @_ZnwmSt11align_val_tRKSt9nothrow_t(i64 10, i64 8, ptr nonnull %nt)
116+
%call3 = call ptr @_ZnwmSt11align_val_tRKSt9nothrow_t(i64 10, i64 8, ptr %nt) #6
117+
call void @dummy(ptr %call3)
102118
ret void
103119
}
104120

@@ -118,6 +134,10 @@ define void @array_new() {
118134
; HOTCOLD: @_Znam12__hot_cold_t(i64 10, i8 [[HOT]])
119135
%call2 = call ptr @_Znam(i64 10) #2
120136
call void @dummy(ptr %call2)
137+
;; Attribute cold on a nobuiltin call has no effect.
138+
; HOTCOLD: @_Znam(i64 10)
139+
%call3 = call ptr @_Znam(i64 10) #6
140+
call void @dummy(ptr %call3)
121141
ret void
122142
}
123143

@@ -138,6 +158,10 @@ define void @array_new_align() {
138158
; HOTCOLD: @_ZnamSt11align_val_t12__hot_cold_t(i64 10, i64 8, i8 [[HOT]])
139159
%call2 = call ptr @_ZnamSt11align_val_t(i64 10, i64 8) #2
140160
call void @dummy(ptr %call2)
161+
;; Attribute cold on a nobuiltin call has no effect.
162+
; HOTCOLD: @_ZnamSt11align_val_t(i64 10, i64 8)
163+
%call3 = call ptr @_ZnamSt11align_val_t(i64 10, i64 8) #6
164+
call void @dummy(ptr %call3)
141165
ret void
142166
}
143167

@@ -159,6 +183,10 @@ define void @array_new_nothrow() {
159183
; HOTCOLD: @_ZnamRKSt9nothrow_t12__hot_cold_t(i64 10, ptr nonnull %nt, i8 [[HOT]])
160184
%call2 = call ptr @_ZnamRKSt9nothrow_t(i64 10, ptr %nt) #2
161185
call void @dummy(ptr %call2)
186+
;; Attribute cold on a nobuiltin call has no effect.
187+
; HOTCOLD: @_ZnamRKSt9nothrow_t(i64 10, ptr nonnull %nt)
188+
%call3 = call ptr @_ZnamRKSt9nothrow_t(i64 10, ptr %nt) #6
189+
call void @dummy(ptr %call3)
162190
ret void
163191
}
164192

@@ -181,6 +209,10 @@ define void @array_new_align_nothrow() {
181209
; HOTCOLD: @_ZnamSt11align_val_tRKSt9nothrow_t12__hot_cold_t(i64 10, i64 8, ptr nonnull %nt, i8 [[HOT]])
182210
%call2 = call ptr @_ZnamSt11align_val_tRKSt9nothrow_t(i64 10, i64 8, ptr %nt) #2
183211
call void @dummy(ptr %call2)
212+
;; Attribute cold on a nobuiltin call has no effect.
213+
; HOTCOLD: @_ZnamSt11align_val_tRKSt9nothrow_t(i64 10, i64 8, ptr nonnull %nt)
214+
%call3 = call ptr @_ZnamSt11align_val_tRKSt9nothrow_t(i64 10, i64 8, ptr %nt) #6
215+
call void @dummy(ptr %call3)
184216
ret void
185217
}
186218

@@ -200,6 +232,10 @@ define void @new_hot_cold() {
200232
; HOTCOLD: @_Znwm12__hot_cold_t(i64 10, i8 [[PREVHINTHOT]])
201233
%call2 = call ptr @_Znwm12__hot_cold_t(i64 10, i8 7) #2
202234
call void @dummy(ptr %call2)
235+
;; Attribute cold on a nobuiltin existing hot/cold call updates the hint.
236+
; HOTCOLD: @_Znwm12__hot_cold_t(i64 10, i8 [[PREVHINTCOLD]])
237+
%call3 = call ptr @_Znwm12__hot_cold_t(i64 10, i8 7) #6
238+
call void @dummy(ptr %call3)
203239
ret void
204240
}
205241

@@ -219,6 +255,10 @@ define void @new_align_hot_cold() {
219255
; HOTCOLD: @_ZnwmSt11align_val_t12__hot_cold_t(i64 10, i64 8, i8 [[PREVHINTHOT]])
220256
%call2 = call ptr @_ZnwmSt11align_val_t12__hot_cold_t(i64 10, i64 8, i8 7) #2
221257
call void @dummy(ptr %call2)
258+
;; Attribute cold on a nobuiltin existing hot/cold call updates the hint.
259+
; HOTCOLD: @_ZnwmSt11align_val_t12__hot_cold_t(i64 10, i64 8, i8 [[PREVHINTCOLD]])
260+
%call3 = call ptr @_ZnwmSt11align_val_t12__hot_cold_t(i64 10, i64 8, i8 7) #6
261+
call void @dummy(ptr %call3)
222262
ret void
223263
}
224264

@@ -239,6 +279,10 @@ define void @new_nothrow_hot_cold() {
239279
; HOTCOLD: @_ZnwmRKSt9nothrow_t12__hot_cold_t(i64 10, ptr nonnull %nt, i8 [[PREVHINTHOT]])
240280
%call2 = call ptr @_ZnwmRKSt9nothrow_t12__hot_cold_t(i64 10, ptr %nt, i8 7) #2
241281
call void @dummy(ptr %call2)
282+
;; Attribute cold on a nobuiltin existing hot/cold call updates the hint.
283+
; HOTCOLD: @_ZnwmRKSt9nothrow_t12__hot_cold_t(i64 10, ptr nonnull %nt, i8 [[PREVHINTCOLD]])
284+
%call3 = call ptr @_ZnwmRKSt9nothrow_t12__hot_cold_t(i64 10, ptr %nt, i8 7) #6
285+
call void @dummy(ptr %call3)
242286
ret void
243287
}
244288

@@ -259,6 +303,10 @@ define void @new_align_nothrow_hot_cold() {
259303
; HOTCOLD: @_ZnwmSt11align_val_tRKSt9nothrow_t12__hot_cold_t(i64 10, i64 8, ptr nonnull %nt, i8 [[PREVHINTHOT]])
260304
%call2 = call ptr @_ZnwmSt11align_val_tRKSt9nothrow_t12__hot_cold_t(i64 10, i64 8, ptr %nt, i8 7) #2
261305
call void @dummy(ptr %call2)
306+
;; Attribute cold on a nobuiltin existing hot/cold call updates the hint.
307+
; HOTCOLD: @_ZnwmSt11align_val_tRKSt9nothrow_t12__hot_cold_t(i64 10, i64 8, ptr nonnull %nt, i8 [[PREVHINTCOLD]])
308+
%call3 = call ptr @_ZnwmSt11align_val_tRKSt9nothrow_t12__hot_cold_t(i64 10, i64 8, ptr %nt, i8 7) #6
309+
call void @dummy(ptr %call3)
262310
ret void
263311
}
264312

@@ -278,6 +326,10 @@ define void @array_new_hot_cold() {
278326
; HOTCOLD: @_Znam12__hot_cold_t(i64 10, i8 [[PREVHINTHOT]])
279327
%call2 = call ptr @_Znam12__hot_cold_t(i64 10, i8 7) #2
280328
call void @dummy(ptr %call2)
329+
;; Attribute cold on a nobuiltin existing hot/cold call updates the hint.
330+
; HOTCOLD: @_Znam12__hot_cold_t(i64 10, i8 [[PREVHINTCOLD]])
331+
%call3 = call ptr @_Znam12__hot_cold_t(i64 10, i8 7) #6
332+
call void @dummy(ptr %call3)
281333
ret void
282334
}
283335

@@ -297,6 +349,10 @@ define void @array_new_align_hot_cold() {
297349
; HOTCOLD: @_ZnamSt11align_val_t12__hot_cold_t(i64 10, i64 8, i8 [[PREVHINTHOT]])
298350
%call2 = call ptr @_ZnamSt11align_val_t12__hot_cold_t(i64 10, i64 8, i8 7) #2
299351
call void @dummy(ptr %call2)
352+
;; Attribute cold on a nobuiltin existing hot/cold call updates the hint.
353+
; HOTCOLD: @_ZnamSt11align_val_t12__hot_cold_t(i64 10, i64 8, i8 [[PREVHINTCOLD]])
354+
%call3 = call ptr @_ZnamSt11align_val_t12__hot_cold_t(i64 10, i64 8, i8 7) #6
355+
call void @dummy(ptr %call3)
300356
ret void
301357
}
302358

@@ -317,6 +373,10 @@ define void @array_new_nothrow_hot_cold() {
317373
; HOTCOLD: @_ZnamRKSt9nothrow_t12__hot_cold_t(i64 10, ptr nonnull %nt, i8 [[PREVHINTHOT]])
318374
%call2 = call ptr @_ZnamRKSt9nothrow_t12__hot_cold_t(i64 10, ptr %nt, i8 7) #2
319375
call void @dummy(ptr %call2)
376+
;; Attribute cold on a nobuiltin existing hot/cold call updates the hint.
377+
; HOTCOLD: @_ZnamRKSt9nothrow_t12__hot_cold_t(i64 10, ptr nonnull %nt, i8 [[PREVHINTCOLD]])
378+
%call3 = call ptr @_ZnamRKSt9nothrow_t12__hot_cold_t(i64 10, ptr %nt, i8 7) #6
379+
call void @dummy(ptr %call3)
320380
ret void
321381
}
322382

@@ -337,6 +397,10 @@ define void @array_new_align_nothrow_hot_cold() {
337397
; HOTCOLD: @_ZnamSt11align_val_tRKSt9nothrow_t12__hot_cold_t(i64 10, i64 8, ptr nonnull %nt, i8 [[PREVHINTHOT]])
338398
%call2 = call ptr @_ZnamSt11align_val_tRKSt9nothrow_t12__hot_cold_t(i64 10, i64 8, ptr %nt, i8 7) #2
339399
call void @dummy(ptr %call2)
400+
;; Attribute cold on a nobuiltin existing hot/cold call updates the hint.
401+
; HOTCOLD: @_ZnamSt11align_val_tRKSt9nothrow_t12__hot_cold_t(i64 10, i64 8, ptr nonnull %nt, i8 [[PREVHINTCOLD]])
402+
%call3 = call ptr @_ZnamSt11align_val_tRKSt9nothrow_t12__hot_cold_t(i64 10, i64 8, ptr %nt, i8 7) #6
403+
call void @dummy(ptr %call3)
340404
ret void
341405
}
342406

@@ -359,6 +423,11 @@ define void @size_returning_test() {
359423
%call2 = call {ptr, i64} @__size_returning_new(i64 10) #5
360424
%p2 = extractvalue {ptr, i64} %call2, 0
361425
call void @dummy(ptr %p2)
426+
;; Attribute cold on a nobuiltin call has no effect.
427+
; HOTCOLD: @__size_returning_new(i64 10)
428+
%call3 = call {ptr, i64} @__size_returning_new(i64 10) #6
429+
%p3 = extractvalue {ptr, i64} %call3, 0
430+
call void @dummy(ptr %p3)
362431
ret void
363432
}
364433

@@ -381,6 +450,11 @@ define void @size_returning_aligned_test() {
381450
%call2 = call {ptr, i64} @__size_returning_new_aligned(i64 10, i64 8) #5
382451
%p2 = extractvalue {ptr, i64} %call2, 0
383452
call void @dummy(ptr %p2)
453+
;; Attribute cold on a nobuiltin call has no effect.
454+
; HOTCOLD: @__size_returning_new_aligned(i64 10, i64 8)
455+
%call3 = call {ptr, i64} @__size_returning_new_aligned(i64 10, i64 8) #6
456+
%p3 = extractvalue {ptr, i64} %call3, 0
457+
call void @dummy(ptr %p3)
384458
ret void
385459
}
386460

@@ -403,6 +477,11 @@ define void @size_returning_update_test() {
403477
%call2 = call {ptr, i64} @__size_returning_new_hot_cold(i64 10, i8 7) #5
404478
%p2 = extractvalue {ptr, i64} %call2, 0
405479
call void @dummy(ptr %p2)
480+
;; Attribute cold on a nobuiltin existing hot/cold call updates the hint.
481+
; HOTCOLD: @__size_returning_new_hot_cold(i64 10, i8 [[PREVHINTCOLD]])
482+
%call3 = call {ptr, i64} @__size_returning_new_hot_cold(i64 10, i8 7) #6
483+
%p3 = extractvalue {ptr, i64} %call3, 0
484+
call void @dummy(ptr %p3)
406485
ret void
407486
}
408487

@@ -425,6 +504,11 @@ define void @size_returning_aligned_update_test() {
425504
%call2 = call {ptr, i64} @__size_returning_new_aligned_hot_cold(i64 10, i64 8, i8 7) #5
426505
%p2 = extractvalue {ptr, i64} %call2, 0
427506
call void @dummy(ptr %p2)
507+
;; Attribute cold on a nobuiltin existing hot/cold call updates the hint.
508+
; HOTCOLD: @__size_returning_new_aligned_hot_cold(i64 10, i64 8, i8 [[PREVHINTCOLD]])
509+
%call3 = call {ptr, i64} @__size_returning_new_aligned_hot_cold(i64 10, i64 8, i8 7) #6
510+
%p3 = extractvalue {ptr, i64} %call3, 0
511+
call void @dummy(ptr %p3)
428512
ret void
429513
}
430514

@@ -463,3 +547,5 @@ attributes #2 = { builtin allocsize(0) "memprof"="hot" }
463547
attributes #3 = { "memprof" = "cold" }
464548
attributes #4 = { "memprof" = "notcold" }
465549
attributes #5 = { "memprof" = "hot" }
550+
551+
attributes #6 = { nobuiltin allocsize(0) "memprof"="cold" }

0 commit comments

Comments
 (0)