Skip to content

Commit 92e399b

Browse files
committed
[𝘀𝗽𝗿] initial version
Created using spr 1.3.8-beta.1
2 parents 362de22 + 0b24571 commit 92e399b

File tree

8 files changed

+199
-41
lines changed

8 files changed

+199
-41
lines changed

clang/lib/CodeGen/BackendUtil.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1144,7 +1144,12 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
11441144
if (!IsThinLTOPostLink) {
11451145
addSanitizers(TargetTriple, CodeGenOpts, LangOpts, PB);
11461146
addKCFIPass(TargetTriple, LangOpts, PB);
1147-
addAllocTokenPass(TargetTriple, CodeGenOpts, LangOpts, PB);
1147+
1148+
// If this is a ThinLTO pre-link compile, skip AllocTokenPass; it will be
1149+
// added during ThinLTO backend compile phase to enable optimizations such
1150+
// as MemProf to remain compatible with AllocToken instrumentation.
1151+
if (!CodeGenOpts.PrepareForThinLTO)
1152+
addAllocTokenPass(TargetTriple, CodeGenOpts, LangOpts, PB);
11481153
}
11491154

11501155
if (std::optional<GCOVOptions> Options =
@@ -1425,6 +1430,12 @@ runThinLTOBackend(CompilerInstance &CI, ModuleSummaryIndex *CombinedIndex,
14251430
Conf.RemarksFormat = CGOpts.OptRecordFormat;
14261431
Conf.SplitDwarfFile = CGOpts.SplitDwarfFile;
14271432
Conf.SplitDwarfOutput = CGOpts.SplitDwarfOutput;
1433+
Conf.PassBuilderCallback = [&](PassBuilder &PB) {
1434+
// Skipped during pre-link phase to avoid instrumentation interfering with
1435+
// backend optimizations, and instead we run it as late as possible in the
1436+
// backend phase.
1437+
addAllocTokenPass(CI.getTarget().getTriple(), CGOpts, CI.getLangOpts(), PB);
1438+
};
14281439
switch (Action) {
14291440
case Backend_EmitNothing:
14301441
Conf.PreCodeGenModuleHook = [](size_t Task, const llvm::Module &Mod) {

clang/test/CodeGen/lto-newpm-pipeline.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,10 @@
4848
// CHECK-THIN-O0-NEXT: Running pass: AlwaysInlinerPass
4949
// CHECK-THIN-O0-NEXT: Running analysis: ProfileSummaryAnalysis
5050
// CHECK-THIN-O0-NEXT: Running pass: CoroConditionalWrapper
51-
// CHECK-THIN-O0-NEXT: Running pass: AllocTokenPass
52-
// CHECK-THIN-O0-NEXT: Running analysis: OptimizationRemarkEmitterAnalysis
53-
// CHECK-THIN-O0-NEXT: Running analysis: TargetLibraryAnalysis
5451
// CHECK-THIN-O0-NEXT: Running pass: CanonicalizeAliasesPass
5552
// CHECK-THIN-O0-NEXT: Running pass: NameAnonGlobalPass
5653
// CHECK-THIN-O0-NEXT: Running pass: AnnotationRemarksPass
54+
// CHECK-THIN-O0-NEXT: Running analysis: TargetLibraryAnalysis
5755
// CHECK-THIN-O0-NEXT: Running pass: VerifierPass
5856
// CHECK-THIN-O0-NEXT: Running pass: ThinLTOBitcodeWriterPass
5957

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Test end-to-end ThinLTO optimization pipeline with PGHO, that it does not
2+
// interfere with other allocation instrumentation features.
3+
//
4+
// RUN: split-file %s %t
5+
// RUN: llvm-profdata merge %t/memprof.yaml -o %t/use.memprofdata
6+
//
7+
// RUN: %clangxx -O2 -flto=thin -g -fmemory-profile-use=%t/use.memprofdata %t/src.cpp -c -o %t.o
8+
// RUN: llvm-lto2 run %t.o -supports-hot-cold-new -r=%t.o,main,plx -r=%t.o,_Z3foov,plx -r=%t.o,_Znam, -o %t.out
9+
// RUN: %clang_cc1 -O2 -x ir %t.o -fthinlto-index=%t.o.thinlto.bc -mllvm -optimize-hot-cold-new -emit-llvm -o - 2>&1 | FileCheck %s --check-prefixes=CHECK,DEFAULT
10+
//
11+
// RUN: %clangxx -O2 -flto=thin -g -fsanitize=alloc-token -fmemory-profile-use=%t/use.memprofdata %t/src.cpp -c -o %t.o
12+
// RUN: llvm-lto2 run %t.o -supports-hot-cold-new -r=%t.o,main,plx -r=%t.o,_Z3foov,plx -r=%t.o,_Znam, -o %t.out
13+
// RUN: %clang_cc1 -O2 -x ir %t.o -fsanitize=alloc-token -fthinlto-index=%t.o.thinlto.bc -mllvm -optimize-hot-cold-new -emit-llvm -o - 2>&1 | FileCheck %s --check-prefixes=CHECK,ALLOCTOKEN
14+
15+
//--- memprof.yaml
16+
---
17+
HeapProfileRecords:
18+
- GUID: 0x7f8d88fcc70a347b
19+
AllocSites:
20+
- Callstack:
21+
- { Function: 0x7f8d88fcc70a347b, LineOffset: 1, Column: 10, IsInlineFrame: false }
22+
- { Function: 0xdb956436e78dd5fa, LineOffset: 1, Column: 13, IsInlineFrame: false }
23+
MemInfoBlock:
24+
AllocCount: 1
25+
TotalAccessCount: 0
26+
MinAccessCount: 0
27+
MaxAccessCount: 0
28+
TotalSize: 10
29+
MinSize: 10
30+
MaxSize: 10
31+
AllocTimestamp: 100
32+
DeallocTimestamp: 100
33+
TotalLifetime: 100000
34+
MinLifetime: 100000
35+
MaxLifetime: 100000
36+
AllocCpuId: 0
37+
DeallocCpuId: 0
38+
NumMigratedCpu: 0
39+
NumLifetimeOverlaps: 0
40+
NumSameAllocCpu: 0
41+
NumSameDeallocCpu: 0
42+
DataTypeId: 0
43+
TotalAccessDensity: 0
44+
MinAccessDensity: 0
45+
MaxAccessDensity: 0
46+
TotalLifetimeAccessDensity: 0
47+
MinLifetimeAccessDensity: 0
48+
MaxLifetimeAccessDensity: 0
49+
AccessHistogramSize: 0
50+
AccessHistogram: 0
51+
...
52+
53+
//--- src.cpp
54+
// CHECK-LABEL: define{{.*}} ptr @_Z3foov()
55+
// DEFAULT: call {{.*}} ptr @_Znam12__hot_cold_t(i64 10, i8 -128)
56+
// ALLOCTOKEN: call {{.*}} ptr @__alloc_token__Znam12__hot_cold_t(i64 10, i8 -128, i64 1538840549748785101){{.*}} !alloc_token
57+
char *foo() {
58+
return new char[10];
59+
}
60+
61+
int main() {
62+
char *a = foo();
63+
delete[] a;
64+
return 0;
65+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Test end-to-end optimization pipeline with PGHO, that it does not interfere
2+
// with other allocation instrumentation features.
3+
//
4+
// RUN: split-file %s %t
5+
// RUN: llvm-profdata merge %t/memprof.yaml -o %t/use.profdata
6+
// RUN: %clang_cc1 -O2 -debug-info-kind=limited -fmemory-profile-use=%t/use.profdata -mllvm -optimize-hot-cold-new \
7+
// RUN: %t/src.cpp -triple x86_64-linux-gnu -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,DEFAULT
8+
// RUN: %clang_cc1 -O2 -fsanitize=alloc-token -debug-info-kind=limited -fmemory-profile-use=%t/use.profdata -mllvm -optimize-hot-cold-new \
9+
// RUN: %t/src.cpp -triple x86_64-linux-gnu -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,ALLOCTOKEN
10+
11+
//--- memprof.yaml
12+
---
13+
HeapProfileRecords:
14+
- GUID: 0x7f8d88fcc70a347b
15+
AllocSites:
16+
- Callstack:
17+
- { Function: 0x7f8d88fcc70a347b, LineOffset: 1, Column: 10, IsInlineFrame: false }
18+
- { Function: 0xdb956436e78dd5fa, LineOffset: 1, Column: 13, IsInlineFrame: false }
19+
MemInfoBlock:
20+
AllocCount: 1
21+
TotalAccessCount: 0
22+
MinAccessCount: 0
23+
MaxAccessCount: 0
24+
TotalSize: 10
25+
MinSize: 10
26+
MaxSize: 10
27+
AllocTimestamp: 100
28+
DeallocTimestamp: 100
29+
TotalLifetime: 100000
30+
MinLifetime: 100000
31+
MaxLifetime: 100000
32+
AllocCpuId: 0
33+
DeallocCpuId: 0
34+
NumMigratedCpu: 0
35+
NumLifetimeOverlaps: 0
36+
NumSameAllocCpu: 0
37+
NumSameDeallocCpu: 0
38+
DataTypeId: 0
39+
TotalAccessDensity: 0
40+
MinAccessDensity: 0
41+
MaxAccessDensity: 0
42+
TotalLifetimeAccessDensity: 0
43+
MinLifetimeAccessDensity: 0
44+
MaxLifetimeAccessDensity: 0
45+
AccessHistogramSize: 0
46+
AccessHistogram: 0
47+
...
48+
49+
//--- src.cpp
50+
// CHECK-LABEL: define{{.*}} ptr @_Z3foov()
51+
// DEFAULT: call {{.*}} ptr @_Znam12__hot_cold_t(i64 10, i8 -128)
52+
// ALLOCTOKEN: call {{.*}} ptr @__alloc_token__Znam12__hot_cold_t(i64 10, i8 -128, i64 1538840549748785101){{.*}} !alloc_token
53+
char *foo() {
54+
return new char[10];
55+
}
56+
57+
int main() {
58+
char *a = foo();
59+
delete[] a;
60+
return 0;
61+
}

llvm/include/llvm/LTO/Config.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ struct Config {
5151
std::vector<std::string> MAttrs;
5252
std::vector<std::string> MllvmArgs;
5353
std::vector<std::string> PassPlugins;
54+
/// Callback to customize the PassBuilder.
55+
std::function<void(PassBuilder &)> PassBuilderCallback;
5456
/// For adding passes that run right before codegen.
5557
std::function<void(legacy::PassManager &)> PreCodeGenPassesHook;
5658
std::optional<Reloc::Model> RelocModel = Reloc::PIC_;

llvm/lib/LTO/LTOBackend.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,8 @@ static void runNewPMPasses(const Config &Conf, Module &Mod, TargetMachine *TM,
275275
SI.registerCallbacks(PIC, &MAM);
276276
PassBuilder PB(TM, Conf.PTO, PGOOpt, &PIC);
277277

278+
if (Conf.PassBuilderCallback)
279+
Conf.PassBuilderCallback(PB);
278280
RegisterPassPlugins(Conf.PassPlugins, PB);
279281

280282
std::unique_ptr<TargetLibraryInfoImpl> TLII(

llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp

Lines changed: 43 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1806,119 +1806,125 @@ Value *LibCallSimplifier::optimizeNew(CallInst *CI, IRBuilderBase &B,
18061806
// better to replace the hinted call with a non hinted call, to avoid the
18071807
// extra parameter and the if condition check of the hint value in the
18081808
// allocator. This can be considered in the future.
1809+
Value *NewCall = nullptr;
18091810
switch (Func) {
18101811
case LibFunc_Znwm12__hot_cold_t:
18111812
if (OptimizeExistingHotColdNew)
1812-
return emitHotColdNew(CI->getArgOperand(0), B, TLI,
1813-
LibFunc_Znwm12__hot_cold_t, HotCold);
1813+
NewCall = emitHotColdNew(CI->getArgOperand(0), B, TLI,
1814+
LibFunc_Znwm12__hot_cold_t, HotCold);
18141815
break;
18151816
case LibFunc_Znwm:
1816-
return emitHotColdNew(CI->getArgOperand(0), B, TLI,
1817-
LibFunc_Znwm12__hot_cold_t, HotCold);
1817+
NewCall = emitHotColdNew(CI->getArgOperand(0), B, TLI,
1818+
LibFunc_Znwm12__hot_cold_t, HotCold);
18181819
break;
18191820
case LibFunc_Znam12__hot_cold_t:
18201821
if (OptimizeExistingHotColdNew)
1821-
return emitHotColdNew(CI->getArgOperand(0), B, TLI,
1822-
LibFunc_Znam12__hot_cold_t, HotCold);
1822+
NewCall = emitHotColdNew(CI->getArgOperand(0), B, TLI,
1823+
LibFunc_Znam12__hot_cold_t, HotCold);
18231824
break;
18241825
case LibFunc_Znam:
1825-
return emitHotColdNew(CI->getArgOperand(0), B, TLI,
1826-
LibFunc_Znam12__hot_cold_t, HotCold);
1826+
NewCall = emitHotColdNew(CI->getArgOperand(0), B, TLI,
1827+
LibFunc_Znam12__hot_cold_t, HotCold);
18271828
break;
18281829
case LibFunc_ZnwmRKSt9nothrow_t12__hot_cold_t:
18291830
if (OptimizeExistingHotColdNew)
1830-
return emitHotColdNewNoThrow(
1831+
NewCall = emitHotColdNewNoThrow(
18311832
CI->getArgOperand(0), CI->getArgOperand(1), B, TLI,
18321833
LibFunc_ZnwmRKSt9nothrow_t12__hot_cold_t, HotCold);
18331834
break;
18341835
case LibFunc_ZnwmRKSt9nothrow_t:
1835-
return emitHotColdNewNoThrow(CI->getArgOperand(0), CI->getArgOperand(1), B,
1836-
TLI, LibFunc_ZnwmRKSt9nothrow_t12__hot_cold_t,
1837-
HotCold);
1836+
NewCall = emitHotColdNewNoThrow(
1837+
CI->getArgOperand(0), CI->getArgOperand(1), B, TLI,
1838+
LibFunc_ZnwmRKSt9nothrow_t12__hot_cold_t, HotCold);
18381839
break;
18391840
case LibFunc_ZnamRKSt9nothrow_t12__hot_cold_t:
18401841
if (OptimizeExistingHotColdNew)
1841-
return emitHotColdNewNoThrow(
1842+
NewCall = emitHotColdNewNoThrow(
18421843
CI->getArgOperand(0), CI->getArgOperand(1), B, TLI,
18431844
LibFunc_ZnamRKSt9nothrow_t12__hot_cold_t, HotCold);
18441845
break;
18451846
case LibFunc_ZnamRKSt9nothrow_t:
1846-
return emitHotColdNewNoThrow(CI->getArgOperand(0), CI->getArgOperand(1), B,
1847-
TLI, LibFunc_ZnamRKSt9nothrow_t12__hot_cold_t,
1848-
HotCold);
1847+
NewCall = emitHotColdNewNoThrow(
1848+
CI->getArgOperand(0), CI->getArgOperand(1), B, TLI,
1849+
LibFunc_ZnamRKSt9nothrow_t12__hot_cold_t, HotCold);
18491850
break;
18501851
case LibFunc_ZnwmSt11align_val_t12__hot_cold_t:
18511852
if (OptimizeExistingHotColdNew)
1852-
return emitHotColdNewAligned(
1853+
NewCall = emitHotColdNewAligned(
18531854
CI->getArgOperand(0), CI->getArgOperand(1), B, TLI,
18541855
LibFunc_ZnwmSt11align_val_t12__hot_cold_t, HotCold);
18551856
break;
18561857
case LibFunc_ZnwmSt11align_val_t:
1857-
return emitHotColdNewAligned(CI->getArgOperand(0), CI->getArgOperand(1), B,
1858-
TLI, LibFunc_ZnwmSt11align_val_t12__hot_cold_t,
1859-
HotCold);
1858+
NewCall = emitHotColdNewAligned(
1859+
CI->getArgOperand(0), CI->getArgOperand(1), B, TLI,
1860+
LibFunc_ZnwmSt11align_val_t12__hot_cold_t, HotCold);
18601861
break;
18611862
case LibFunc_ZnamSt11align_val_t12__hot_cold_t:
18621863
if (OptimizeExistingHotColdNew)
1863-
return emitHotColdNewAligned(
1864+
NewCall = emitHotColdNewAligned(
18641865
CI->getArgOperand(0), CI->getArgOperand(1), B, TLI,
18651866
LibFunc_ZnamSt11align_val_t12__hot_cold_t, HotCold);
18661867
break;
18671868
case LibFunc_ZnamSt11align_val_t:
1868-
return emitHotColdNewAligned(CI->getArgOperand(0), CI->getArgOperand(1), B,
1869-
TLI, LibFunc_ZnamSt11align_val_t12__hot_cold_t,
1870-
HotCold);
1869+
NewCall = emitHotColdNewAligned(
1870+
CI->getArgOperand(0), CI->getArgOperand(1), B, TLI,
1871+
LibFunc_ZnamSt11align_val_t12__hot_cold_t, HotCold);
18711872
break;
18721873
case LibFunc_ZnwmSt11align_val_tRKSt9nothrow_t12__hot_cold_t:
18731874
if (OptimizeExistingHotColdNew)
1874-
return emitHotColdNewAlignedNoThrow(
1875+
NewCall = emitHotColdNewAlignedNoThrow(
18751876
CI->getArgOperand(0), CI->getArgOperand(1), CI->getArgOperand(2), B,
18761877
TLI, LibFunc_ZnwmSt11align_val_tRKSt9nothrow_t12__hot_cold_t,
18771878
HotCold);
18781879
break;
18791880
case LibFunc_ZnwmSt11align_val_tRKSt9nothrow_t:
1880-
return emitHotColdNewAlignedNoThrow(
1881+
NewCall = emitHotColdNewAlignedNoThrow(
18811882
CI->getArgOperand(0), CI->getArgOperand(1), CI->getArgOperand(2), B,
18821883
TLI, LibFunc_ZnwmSt11align_val_tRKSt9nothrow_t12__hot_cold_t, HotCold);
18831884
break;
18841885
case LibFunc_ZnamSt11align_val_tRKSt9nothrow_t12__hot_cold_t:
18851886
if (OptimizeExistingHotColdNew)
1886-
return emitHotColdNewAlignedNoThrow(
1887+
NewCall = emitHotColdNewAlignedNoThrow(
18871888
CI->getArgOperand(0), CI->getArgOperand(1), CI->getArgOperand(2), B,
18881889
TLI, LibFunc_ZnamSt11align_val_tRKSt9nothrow_t12__hot_cold_t,
18891890
HotCold);
18901891
break;
18911892
case LibFunc_ZnamSt11align_val_tRKSt9nothrow_t:
1892-
return emitHotColdNewAlignedNoThrow(
1893+
NewCall = emitHotColdNewAlignedNoThrow(
18931894
CI->getArgOperand(0), CI->getArgOperand(1), CI->getArgOperand(2), B,
18941895
TLI, LibFunc_ZnamSt11align_val_tRKSt9nothrow_t12__hot_cold_t, HotCold);
18951896
break;
18961897
case LibFunc_size_returning_new:
1897-
return emitHotColdSizeReturningNew(CI->getArgOperand(0), B, TLI,
1898-
LibFunc_size_returning_new_hot_cold,
1899-
HotCold);
1898+
NewCall = emitHotColdSizeReturningNew(CI->getArgOperand(0), B, TLI,
1899+
LibFunc_size_returning_new_hot_cold,
1900+
HotCold);
19001901
break;
19011902
case LibFunc_size_returning_new_hot_cold:
19021903
if (OptimizeExistingHotColdNew)
1903-
return emitHotColdSizeReturningNew(CI->getArgOperand(0), B, TLI,
1904-
LibFunc_size_returning_new_hot_cold,
1905-
HotCold);
1904+
NewCall = emitHotColdSizeReturningNew(CI->getArgOperand(0), B, TLI,
1905+
LibFunc_size_returning_new_hot_cold,
1906+
HotCold);
19061907
break;
19071908
case LibFunc_size_returning_new_aligned:
1908-
return emitHotColdSizeReturningNewAligned(
1909+
NewCall = emitHotColdSizeReturningNewAligned(
19091910
CI->getArgOperand(0), CI->getArgOperand(1), B, TLI,
19101911
LibFunc_size_returning_new_aligned_hot_cold, HotCold);
19111912
break;
19121913
case LibFunc_size_returning_new_aligned_hot_cold:
19131914
if (OptimizeExistingHotColdNew)
1914-
return emitHotColdSizeReturningNewAligned(
1915+
NewCall = emitHotColdSizeReturningNewAligned(
19151916
CI->getArgOperand(0), CI->getArgOperand(1), B, TLI,
19161917
LibFunc_size_returning_new_aligned_hot_cold, HotCold);
19171918
break;
19181919
default:
19191920
return nullptr;
19201921
}
1921-
return nullptr;
1922+
1923+
if (auto *NewCI = dyn_cast_or_null<Instruction>(NewCall))
1924+
if (MDNode *MD = CI->getMetadata(LLVMContext::MD_alloc_token))
1925+
NewCI->setMetadata(LLVMContext::MD_alloc_token, MD);
1926+
1927+
return NewCall;
19221928
}
19231929

19241930
//===----------------------------------------------------------------------===//

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,16 @@ define void @size_returning_aligned_update_test() {
610610
ret void
611611
}
612612

613+
;; Check that !alloc_token is preserved.
614+
; HOTCOLD-LABEL: @new_alloc_token()
615+
define void @new_alloc_token() {
616+
;; Attribute cold converted to __hot_cold_t cold value.
617+
; HOTCOLD: @_Znwm12__hot_cold_t(i64 10, i8 [[COLD]]), !alloc_token ![[ALLOC_TOKEN:[0-9]+]]
618+
%call = call ptr @_Znwm(i64 10) #0, !alloc_token !0
619+
call void @dummy(ptr %call)
620+
ret void
621+
}
622+
613623
;; So that instcombine doesn't optimize out the call.
614624
declare void @dummy(ptr)
615625

@@ -649,3 +659,6 @@ attributes #5 = { "memprof" = "hot" }
649659
attributes #8 = { "memprof" = "ambiguous" }
650660

651661
attributes #6 = { nobuiltin allocsize(0) "memprof"="cold" }
662+
663+
; CHECK: [[ALLOC_TOKEN]] = !{!"MyType", i1 false}
664+
!0 = !{!"MyType", i1 false}

0 commit comments

Comments
 (0)