Skip to content

Commit 3c6864a

Browse files
authored
[Clang][CodeGen] Remove explicit insertion of AllocToken pass (#169360)
Remove explicit insertion of the AllocTokenPass, which is now handled by the PassBuilder. Emit AllocToken configuration as LLVM module flags to persist into the backend. Specifically, this also means it will now be handled by LTO backend phases; this avoids interference with other optimizations (e.g. PGHO) and enable late heap-allocation optimizations with LTO enabled.
1 parent ca7edf2 commit 3c6864a

File tree

6 files changed

+128
-39
lines changed

6 files changed

+128
-39
lines changed

clang/lib/CodeGen/BackendUtil.cpp

Lines changed: 14 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@
6666
#include "llvm/Transforms/InstCombine/InstCombine.h"
6767
#include "llvm/Transforms/Instrumentation/AddressSanitizer.h"
6868
#include "llvm/Transforms/Instrumentation/AddressSanitizerOptions.h"
69-
#include "llvm/Transforms/Instrumentation/AllocToken.h"
7069
#include "llvm/Transforms/Instrumentation/BoundsChecking.h"
7170
#include "llvm/Transforms/Instrumentation/DataFlowSanitizer.h"
7271
#include "llvm/Transforms/Instrumentation/GCOVProfiler.h"
@@ -234,18 +233,6 @@ class EmitAssemblyHelper {
234233
};
235234
} // namespace
236235

237-
static AllocTokenOptions getAllocTokenOptions(const LangOptions &LangOpts,
238-
const CodeGenOptions &CGOpts) {
239-
AllocTokenOptions Opts;
240-
if (LangOpts.AllocTokenMode)
241-
Opts.Mode = *LangOpts.AllocTokenMode;
242-
if (LangOpts.AllocTokenMax)
243-
Opts.MaxTokens = *LangOpts.AllocTokenMax;
244-
Opts.Extended = CGOpts.SanitizeAllocTokenExtended;
245-
Opts.FastABI = CGOpts.SanitizeAllocTokenFastABI;
246-
return Opts;
247-
}
248-
249236
static SanitizerCoverageOptions
250237
getSancovOptsFromCGOpts(const CodeGenOptions &CGOpts) {
251238
SanitizerCoverageOptions Opts;
@@ -874,23 +861,6 @@ static void addSanitizers(const Triple &TargetTriple,
874861
}
875862
}
876863

877-
static void addAllocTokenPass(const Triple &TargetTriple,
878-
const CodeGenOptions &CodeGenOpts,
879-
const LangOptions &LangOpts, PassBuilder &PB) {
880-
PB.registerOptimizerLastEPCallback([&](ModulePassManager &MPM,
881-
OptimizationLevel Level,
882-
ThinOrFullLTOPhase) {
883-
if (Level == OptimizationLevel::O0 &&
884-
LangOpts.Sanitize.has(SanitizerKind::AllocToken)) {
885-
// The default pass builder only infers libcall function attrs when
886-
// optimizing, so we insert it here because we need it for accurate
887-
// memory allocation function detection with -fsanitize=alloc-token.
888-
MPM.addPass(InferFunctionAttrsPass());
889-
}
890-
MPM.addPass(AllocTokenPass(getAllocTokenOptions(LangOpts, CodeGenOpts)));
891-
});
892-
}
893-
894864
void EmitAssemblyHelper::RunOptimizationPipeline(
895865
BackendAction Action, std::unique_ptr<raw_pwrite_stream> &OS,
896866
std::unique_ptr<llvm::ToolOutputFile> &ThinLinkOS, BackendConsumer *BC) {
@@ -1142,12 +1112,23 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
11421112
FPM.addPass(BoundsCheckingPass(Options));
11431113
});
11441114

1145-
// Don't add sanitizers if we are here from ThinLTO PostLink. That already
1146-
// done on PreLink stage.
11471115
if (!IsThinLTOPostLink) {
1116+
// Most sanitizers only run during PreLink stage.
11481117
addSanitizers(TargetTriple, CodeGenOpts, LangOpts, PB);
11491118
addKCFIPass(TargetTriple, LangOpts, PB);
1150-
addAllocTokenPass(TargetTriple, CodeGenOpts, LangOpts, PB);
1119+
1120+
PB.registerPipelineStartEPCallback(
1121+
[&](ModulePassManager &MPM, OptimizationLevel Level) {
1122+
if (Level == OptimizationLevel::O0 &&
1123+
LangOpts.Sanitize.has(SanitizerKind::AllocToken)) {
1124+
// With the default O0 pipeline, LibFunc attrs are not inferred,
1125+
// so we insert it here because we need it for accurate memory
1126+
// allocation function detection with -fsanitize=alloc-token.
1127+
// Note: This could also be added to the default O0 pipeline, but
1128+
// has a non-trivial effect on generated IR size (attributes).
1129+
MPM.addPass(InferFunctionAttrsPass());
1130+
}
1131+
});
11511132
}
11521133

11531134
if (std::optional<GCOVOptions> Options =

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1635,6 +1635,22 @@ void CodeGenModule::EmitBackendOptionsMetadata(
16351635
getModule().addModuleFlag(llvm::Module::Min, "SmallDataLimit",
16361636
CodeGenOpts.SmallDataLimit);
16371637
}
1638+
1639+
// Set AllocToken configuration for backend pipeline.
1640+
if (LangOpts.AllocTokenMode) {
1641+
StringRef S = llvm::getAllocTokenModeAsString(*LangOpts.AllocTokenMode);
1642+
getModule().addModuleFlag(llvm::Module::Error, "alloc-token-mode",
1643+
llvm::MDString::get(VMContext, S));
1644+
}
1645+
if (LangOpts.AllocTokenMax)
1646+
getModule().addModuleFlag(
1647+
llvm::Module::Error, "alloc-token-max",
1648+
llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
1649+
*LangOpts.AllocTokenMax));
1650+
if (CodeGenOpts.SanitizeAllocTokenFastABI)
1651+
getModule().addModuleFlag(llvm::Module::Error, "alloc-token-fast-abi", 1);
1652+
if (CodeGenOpts.SanitizeAllocTokenExtended)
1653+
getModule().addModuleFlag(llvm::Module::Error, "alloc-token-extended", 1);
16381654
}
16391655

16401656
void CodeGenModule::UpdateCompletedType(const TagDecl *TD) {

clang/test/CodeGen/alloc-token-lower.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
// Test optimization pipelines do not interfere with AllocToken lowering, and we
22
// pass on function attributes correctly.
33
//
4-
// RUN: %clang_cc1 -fsanitize=alloc-token -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s
5-
// RUN: %clang_cc1 -O1 -fsanitize=alloc-token -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s
6-
// RUN: %clang_cc1 -O2 -fsanitize=alloc-token -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s
4+
// RUN: %clang_cc1 -fsanitize=alloc-token -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,DEFAULT
5+
// RUN: %clang_cc1 -O1 -fsanitize=alloc-token -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,DEFAULT
6+
// RUN: %clang_cc1 -O2 -fsanitize=alloc-token -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,DEFAULT
7+
// RUN: %clang_cc1 -fsanitize=alloc-token -fsanitize-alloc-token-fast-abi -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,FASTABI
8+
// RUN: %clang_cc1 -O1 -fsanitize=alloc-token -fsanitize-alloc-token-fast-abi -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,FASTABI
9+
// RUN: %clang_cc1 -O2 -fsanitize=alloc-token -fsanitize-alloc-token-fast-abi -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,FASTABI
710

811
typedef __typeof(sizeof(int)) size_t;
912

1013
void *malloc(size_t size);
1114

1215
// CHECK-LABEL: @test_malloc(
13-
// CHECK: call{{.*}} ptr @__alloc_token_malloc(i64 noundef 4, i64 2689373973731826898){{.*}} !alloc_token [[META_INT:![0-9]+]]
16+
// DEFAULT: call{{.*}} ptr @__alloc_token_malloc(i64 noundef 4, i64 2689373973731826898){{.*}} !alloc_token [[META_INT:![0-9]+]]
17+
// FASTABI: call{{.*}} ptr @__alloc_token_2689373973731826898_malloc(i64 noundef 4){{.*}} !alloc_token [[META_INT:![0-9]+]]
1418
void *test_malloc() {
1519
return malloc(sizeof(int));
1620
}
@@ -26,6 +30,7 @@ void *no_sanitize_malloc(size_t size) __attribute__((no_sanitize("alloc-token"))
2630
// allocator will only implement standard allocation functions.
2731
void *nonstandard_malloc(size_t size) __attribute__((malloc));
2832
// CHECK-LABEL: @test_nonlibcall_malloc(
33+
// CHECK-NOT: __alloc_token_
2934
// CHECK: call{{.*}} ptr @nonstandard_malloc(i64 noundef 4){{.*}} !alloc_token [[META_INT]]
3035
void *test_nonlibcall_malloc() {
3136
return nonstandard_malloc(sizeof(int));
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %clang_cc1 -fsanitize=alloc-token -emit-llvm -o - %s | FileCheck %s --check-prefix=DEFAULT
2+
// RUN: %clang_cc1 -fsanitize=alloc-token -falloc-token-mode=increment -emit-llvm -o - %s | FileCheck %s --check-prefix=INCREMENT
3+
// RUN: %clang_cc1 -fsanitize=alloc-token -falloc-token-max=100 -emit-llvm -o - %s | FileCheck %s --check-prefix=MAX
4+
// RUN: %clang_cc1 -fsanitize=alloc-token -fsanitize-alloc-token-fast-abi -emit-llvm -o - %s | FileCheck %s --check-prefix=FASTABI
5+
// RUN: %clang_cc1 -fsanitize=alloc-token -fsanitize-alloc-token-extended -emit-llvm -o - %s | FileCheck %s --check-prefix=EXTENDED
6+
7+
// DEFAULT-NOT: !"alloc-token-mode"
8+
// DEFAULT-NOT: !"alloc-token-max"
9+
// DEFAULT-NOT: !"alloc-token-fast-abi"
10+
// DEFAULT-NOT: !"alloc-token-extended"
11+
12+
// INCREMENT: !llvm.module.flags = !{{{.*}}![[FLAG:[0-9]+]]{{.*}}}
13+
// INCREMENT: ![[FLAG]] = !{i32 1, !"alloc-token-mode", !"increment"}
14+
15+
// MAX: !llvm.module.flags = !{{{.*}}![[FLAG:[0-9]+]]{{.*}}}
16+
// MAX: ![[FLAG]] = !{i32 1, !"alloc-token-max", i64 100}
17+
18+
// FASTABI: !llvm.module.flags = !{{{.*}}![[FLAG:[0-9]+]]{{.*}}}
19+
// FASTABI: ![[FLAG]] = !{i32 1, !"alloc-token-fast-abi", i32 1}
20+
21+
// EXTENDED: !llvm.module.flags = !{{{.*}}![[FLAG:[0-9]+]]{{.*}}}
22+
// EXTENDED: ![[FLAG]] = !{i32 1, !"alloc-token-extended", i32 1}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
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 --target=x86_64-linux-gnu -O2 -flto=thin -g -fmemory-profile-use=%t/use.memprofdata %t/src.cpp -c -o %t.o
8+
// RUN: llvm-lto2 run %t.o -thinlto-distributed-indexes -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 -triple x86_64-linux-gnu -O1 -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+
// RUN: %clang_cc1 -triple x86_64-linux-gnu -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
11+
//
12+
// RUN: %clangxx --target=x86_64-linux-gnu -O2 -flto=thin -g -fsanitize=alloc-token -falloc-token-max=32 -fmemory-profile-use=%t/use.memprofdata %t/src.cpp -c -o %t.o
13+
// RUN: llvm-lto2 run %t.o -thinlto-distributed-indexes -supports-hot-cold-new -r=%t.o,main,plx -r=%t.o,_Z3foov,plx -r=%t.o,_Znam, -o %t.out
14+
// RUN: %clang_cc1 -triple x86_64-linux-gnu -O1 -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
15+
// RUN: %clang_cc1 -triple x86_64-linux-gnu -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
16+
17+
//--- memprof.yaml
18+
---
19+
HeapProfileRecords:
20+
- GUID: 0x7f8d88fcc70a347b
21+
AllocSites:
22+
- Callstack:
23+
- { Function: 0x7f8d88fcc70a347b, LineOffset: 1, Column: 10, IsInlineFrame: false }
24+
- { Function: 0xdb956436e78dd5fa, LineOffset: 1, Column: 13, IsInlineFrame: false }
25+
MemInfoBlock:
26+
AllocCount: 1
27+
TotalAccessCount: 0
28+
MinAccessCount: 0
29+
MaxAccessCount: 0
30+
TotalSize: 10
31+
MinSize: 10
32+
MaxSize: 10
33+
AllocTimestamp: 100
34+
DeallocTimestamp: 100
35+
TotalLifetime: 100000
36+
MinLifetime: 100000
37+
MaxLifetime: 100000
38+
AllocCpuId: 0
39+
DeallocCpuId: 0
40+
NumMigratedCpu: 0
41+
NumLifetimeOverlaps: 0
42+
NumSameAllocCpu: 0
43+
NumSameDeallocCpu: 0
44+
DataTypeId: 0
45+
TotalAccessDensity: 0
46+
MinAccessDensity: 0
47+
MaxAccessDensity: 0
48+
TotalLifetimeAccessDensity: 0
49+
MinLifetimeAccessDensity: 0
50+
MaxLifetimeAccessDensity: 0
51+
AccessHistogramSize: 0
52+
AccessHistogram: 0
53+
...
54+
55+
//--- src.cpp
56+
// CHECK-LABEL: define{{.*}} ptr @_Z3foov()
57+
// DEFAULT: call {{.*}} ptr @_Znam12__hot_cold_t(i64 10, i8 -128)
58+
// ALLOCTOKEN: call {{.*}} ptr @__alloc_token__Znam12__hot_cold_t(i64 10, i8 -128, i64 12){{.*}} !alloc_token
59+
char *foo() {
60+
return new char[10];
61+
}
62+
63+
int main() {
64+
char *a = foo();
65+
delete[] a;
66+
return 0;
67+
}

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
// CHECK-FULL-O0-NEXT: Running pass: AlwaysInlinerPass
3333
// CHECK-FULL-O0-NEXT: Running analysis: ProfileSummaryAnalysis
3434
// CHECK-FULL-O0-NEXT: Running pass: CoroConditionalWrapper
35-
// CHECK-FULL-O0-NEXT: Running pass: AllocTokenPass
3635
// CHECK-FULL-O0-NEXT: Running pass: CanonicalizeAliasesPass
3736
// CHECK-FULL-O0-NEXT: Running pass: NameAnonGlobalPass
3837
// CHECK-FULL-O0-NEXT: Running pass: AnnotationRemarksPass
@@ -47,7 +46,6 @@
4746
// CHECK-THIN-O0-NEXT: Running pass: AlwaysInlinerPass
4847
// CHECK-THIN-O0-NEXT: Running analysis: ProfileSummaryAnalysis
4948
// CHECK-THIN-O0-NEXT: Running pass: CoroConditionalWrapper
50-
// CHECK-THIN-O0-NEXT: Running pass: AllocTokenPass
5149
// CHECK-THIN-O0-NEXT: Running pass: CanonicalizeAliasesPass
5250
// CHECK-THIN-O0-NEXT: Running pass: NameAnonGlobalPass
5351
// CHECK-THIN-O0-NEXT: Running pass: AnnotationRemarksPass

0 commit comments

Comments
 (0)