Author: Marco Elver Date: 2025-12-02T16:13:45+01:00 New Revision: 3c6864ab8879f7274e6c24c3b7c8e8139cd135dd
URL: https://github.com/llvm/llvm-project/commit/3c6864ab8879f7274e6c24c3b7c8e8139cd135dd DIFF: https://github.com/llvm/llvm-project/commit/3c6864ab8879f7274e6c24c3b7c8e8139cd135dd.diff LOG: [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. Added: clang/test/CodeGen/alloc-token-module-flags.c clang/test/CodeGen/distributed-thin-lto/memprof-pgho.cpp Modified: clang/lib/CodeGen/BackendUtil.cpp clang/lib/CodeGen/CodeGenModule.cpp clang/test/CodeGen/alloc-token-lower.c clang/test/CodeGen/lto-newpm-pipeline.c Removed: ################################################################################ diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index 6d4e575273d8f..ec609db8d3a3c 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -66,7 +66,6 @@ #include "llvm/Transforms/InstCombine/InstCombine.h" #include "llvm/Transforms/Instrumentation/AddressSanitizer.h" #include "llvm/Transforms/Instrumentation/AddressSanitizerOptions.h" -#include "llvm/Transforms/Instrumentation/AllocToken.h" #include "llvm/Transforms/Instrumentation/BoundsChecking.h" #include "llvm/Transforms/Instrumentation/DataFlowSanitizer.h" #include "llvm/Transforms/Instrumentation/GCOVProfiler.h" @@ -234,18 +233,6 @@ class EmitAssemblyHelper { }; } // namespace -static AllocTokenOptions getAllocTokenOptions(const LangOptions &LangOpts, - const CodeGenOptions &CGOpts) { - AllocTokenOptions Opts; - if (LangOpts.AllocTokenMode) - Opts.Mode = *LangOpts.AllocTokenMode; - if (LangOpts.AllocTokenMax) - Opts.MaxTokens = *LangOpts.AllocTokenMax; - Opts.Extended = CGOpts.SanitizeAllocTokenExtended; - Opts.FastABI = CGOpts.SanitizeAllocTokenFastABI; - return Opts; -} - static SanitizerCoverageOptions getSancovOptsFromCGOpts(const CodeGenOptions &CGOpts) { SanitizerCoverageOptions Opts; @@ -874,23 +861,6 @@ static void addSanitizers(const Triple &TargetTriple, } } -static void addAllocTokenPass(const Triple &TargetTriple, - const CodeGenOptions &CodeGenOpts, - const LangOptions &LangOpts, PassBuilder &PB) { - PB.registerOptimizerLastEPCallback([&](ModulePassManager &MPM, - OptimizationLevel Level, - ThinOrFullLTOPhase) { - if (Level == OptimizationLevel::O0 && - LangOpts.Sanitize.has(SanitizerKind::AllocToken)) { - // The default pass builder only infers libcall function attrs when - // optimizing, so we insert it here because we need it for accurate - // memory allocation function detection with -fsanitize=alloc-token. - MPM.addPass(InferFunctionAttrsPass()); - } - MPM.addPass(AllocTokenPass(getAllocTokenOptions(LangOpts, CodeGenOpts))); - }); -} - void EmitAssemblyHelper::RunOptimizationPipeline( BackendAction Action, std::unique_ptr<raw_pwrite_stream> &OS, std::unique_ptr<llvm::ToolOutputFile> &ThinLinkOS, BackendConsumer *BC) { @@ -1142,12 +1112,23 @@ void EmitAssemblyHelper::RunOptimizationPipeline( FPM.addPass(BoundsCheckingPass(Options)); }); - // Don't add sanitizers if we are here from ThinLTO PostLink. That already - // done on PreLink stage. if (!IsThinLTOPostLink) { + // Most sanitizers only run during PreLink stage. addSanitizers(TargetTriple, CodeGenOpts, LangOpts, PB); addKCFIPass(TargetTriple, LangOpts, PB); - addAllocTokenPass(TargetTriple, CodeGenOpts, LangOpts, PB); + + PB.registerPipelineStartEPCallback( + [&](ModulePassManager &MPM, OptimizationLevel Level) { + if (Level == OptimizationLevel::O0 && + LangOpts.Sanitize.has(SanitizerKind::AllocToken)) { + // With the default O0 pipeline, LibFunc attrs are not inferred, + // so we insert it here because we need it for accurate memory + // allocation function detection with -fsanitize=alloc-token. + // Note: This could also be added to the default O0 pipeline, but + // has a non-trivial effect on generated IR size (attributes). + MPM.addPass(InferFunctionAttrsPass()); + } + }); } if (std::optional<GCOVOptions> Options = diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 4789c6b26797f..a04d606b6a0e5 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -1635,6 +1635,22 @@ void CodeGenModule::EmitBackendOptionsMetadata( getModule().addModuleFlag(llvm::Module::Min, "SmallDataLimit", CodeGenOpts.SmallDataLimit); } + + // Set AllocToken configuration for backend pipeline. + if (LangOpts.AllocTokenMode) { + StringRef S = llvm::getAllocTokenModeAsString(*LangOpts.AllocTokenMode); + getModule().addModuleFlag(llvm::Module::Error, "alloc-token-mode", + llvm::MDString::get(VMContext, S)); + } + if (LangOpts.AllocTokenMax) + getModule().addModuleFlag( + llvm::Module::Error, "alloc-token-max", + llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), + *LangOpts.AllocTokenMax)); + if (CodeGenOpts.SanitizeAllocTokenFastABI) + getModule().addModuleFlag(llvm::Module::Error, "alloc-token-fast-abi", 1); + if (CodeGenOpts.SanitizeAllocTokenExtended) + getModule().addModuleFlag(llvm::Module::Error, "alloc-token-extended", 1); } void CodeGenModule::UpdateCompletedType(const TagDecl *TD) { diff --git a/clang/test/CodeGen/alloc-token-lower.c b/clang/test/CodeGen/alloc-token-lower.c index 43d9a6337b7db..2d87b02c6a288 100644 --- a/clang/test/CodeGen/alloc-token-lower.c +++ b/clang/test/CodeGen/alloc-token-lower.c @@ -1,16 +1,20 @@ // Test optimization pipelines do not interfere with AllocToken lowering, and we // pass on function attributes correctly. // -// RUN: %clang_cc1 -fsanitize=alloc-token -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s -// RUN: %clang_cc1 -O1 -fsanitize=alloc-token -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s -// RUN: %clang_cc1 -O2 -fsanitize=alloc-token -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -fsanitize=alloc-token -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,DEFAULT +// RUN: %clang_cc1 -O1 -fsanitize=alloc-token -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,DEFAULT +// RUN: %clang_cc1 -O2 -fsanitize=alloc-token -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,DEFAULT +// 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 +// 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 +// 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 typedef __typeof(sizeof(int)) size_t; void *malloc(size_t size); // CHECK-LABEL: @test_malloc( -// CHECK: call{{.*}} ptr @__alloc_token_malloc(i64 noundef 4, i64 2689373973731826898){{.*}} !alloc_token [[META_INT:![0-9]+]] +// DEFAULT: call{{.*}} ptr @__alloc_token_malloc(i64 noundef 4, i64 2689373973731826898){{.*}} !alloc_token [[META_INT:![0-9]+]] +// FASTABI: call{{.*}} ptr @__alloc_token_2689373973731826898_malloc(i64 noundef 4){{.*}} !alloc_token [[META_INT:![0-9]+]] void *test_malloc() { return malloc(sizeof(int)); } @@ -26,6 +30,7 @@ void *no_sanitize_malloc(size_t size) __attribute__((no_sanitize("alloc-token")) // allocator will only implement standard allocation functions. void *nonstandard_malloc(size_t size) __attribute__((malloc)); // CHECK-LABEL: @test_nonlibcall_malloc( +// CHECK-NOT: __alloc_token_ // CHECK: call{{.*}} ptr @nonstandard_malloc(i64 noundef 4){{.*}} !alloc_token [[META_INT]] void *test_nonlibcall_malloc() { return nonstandard_malloc(sizeof(int)); diff --git a/clang/test/CodeGen/alloc-token-module-flags.c b/clang/test/CodeGen/alloc-token-module-flags.c new file mode 100644 index 0000000000000..6fc0d619915c8 --- /dev/null +++ b/clang/test/CodeGen/alloc-token-module-flags.c @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -fsanitize=alloc-token -emit-llvm -o - %s | FileCheck %s --check-prefix=DEFAULT +// RUN: %clang_cc1 -fsanitize=alloc-token -falloc-token-mode=increment -emit-llvm -o - %s | FileCheck %s --check-prefix=INCREMENT +// RUN: %clang_cc1 -fsanitize=alloc-token -falloc-token-max=100 -emit-llvm -o - %s | FileCheck %s --check-prefix=MAX +// RUN: %clang_cc1 -fsanitize=alloc-token -fsanitize-alloc-token-fast-abi -emit-llvm -o - %s | FileCheck %s --check-prefix=FASTABI +// RUN: %clang_cc1 -fsanitize=alloc-token -fsanitize-alloc-token-extended -emit-llvm -o - %s | FileCheck %s --check-prefix=EXTENDED + +// DEFAULT-NOT: !"alloc-token-mode" +// DEFAULT-NOT: !"alloc-token-max" +// DEFAULT-NOT: !"alloc-token-fast-abi" +// DEFAULT-NOT: !"alloc-token-extended" + +// INCREMENT: !llvm.module.flags = !{{{.*}}![[FLAG:[0-9]+]]{{.*}}} +// INCREMENT: ![[FLAG]] = !{i32 1, !"alloc-token-mode", !"increment"} + +// MAX: !llvm.module.flags = !{{{.*}}![[FLAG:[0-9]+]]{{.*}}} +// MAX: ![[FLAG]] = !{i32 1, !"alloc-token-max", i64 100} + +// FASTABI: !llvm.module.flags = !{{{.*}}![[FLAG:[0-9]+]]{{.*}}} +// FASTABI: ![[FLAG]] = !{i32 1, !"alloc-token-fast-abi", i32 1} + +// EXTENDED: !llvm.module.flags = !{{{.*}}![[FLAG:[0-9]+]]{{.*}}} +// EXTENDED: ![[FLAG]] = !{i32 1, !"alloc-token-extended", i32 1} diff --git a/clang/test/CodeGen/distributed-thin-lto/memprof-pgho.cpp b/clang/test/CodeGen/distributed-thin-lto/memprof-pgho.cpp new file mode 100644 index 0000000000000..ed05962846aff --- /dev/null +++ b/clang/test/CodeGen/distributed-thin-lto/memprof-pgho.cpp @@ -0,0 +1,67 @@ +// Test end-to-end ThinLTO optimization pipeline with PGHO, that it does not +// interfere with other allocation instrumentation features. +// +// RUN: split-file %s %t +// RUN: llvm-profdata merge %t/memprof.yaml -o %t/use.memprofdata +// +// RUN: %clangxx --target=x86_64-linux-gnu -O2 -flto=thin -g -fmemory-profile-use=%t/use.memprofdata %t/src.cpp -c -o %t.o +// 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 +// 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 +// 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 +// +// 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 +// 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 +// 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 +// 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 + +//--- memprof.yaml +--- +HeapProfileRecords: + - GUID: 0x7f8d88fcc70a347b + AllocSites: + - Callstack: + - { Function: 0x7f8d88fcc70a347b, LineOffset: 1, Column: 10, IsInlineFrame: false } + - { Function: 0xdb956436e78dd5fa, LineOffset: 1, Column: 13, IsInlineFrame: false } + MemInfoBlock: + AllocCount: 1 + TotalAccessCount: 0 + MinAccessCount: 0 + MaxAccessCount: 0 + TotalSize: 10 + MinSize: 10 + MaxSize: 10 + AllocTimestamp: 100 + DeallocTimestamp: 100 + TotalLifetime: 100000 + MinLifetime: 100000 + MaxLifetime: 100000 + AllocCpuId: 0 + DeallocCpuId: 0 + NumMigratedCpu: 0 + NumLifetimeOverlaps: 0 + NumSameAllocCpu: 0 + NumSameDeallocCpu: 0 + DataTypeId: 0 + TotalAccessDensity: 0 + MinAccessDensity: 0 + MaxAccessDensity: 0 + TotalLifetimeAccessDensity: 0 + MinLifetimeAccessDensity: 0 + MaxLifetimeAccessDensity: 0 + AccessHistogramSize: 0 + AccessHistogram: 0 +... + +//--- src.cpp +// CHECK-LABEL: define{{.*}} ptr @_Z3foov() +// DEFAULT: call {{.*}} ptr @_Znam12__hot_cold_t(i64 10, i8 -128) +// ALLOCTOKEN: call {{.*}} ptr @__alloc_token__Znam12__hot_cold_t(i64 10, i8 -128, i64 12){{.*}} !alloc_token +char *foo() { + return new char[10]; +} + +int main() { + char *a = foo(); + delete[] a; + return 0; +} diff --git a/clang/test/CodeGen/lto-newpm-pipeline.c b/clang/test/CodeGen/lto-newpm-pipeline.c index 5673c72b49eff..ea9784a76f923 100644 --- a/clang/test/CodeGen/lto-newpm-pipeline.c +++ b/clang/test/CodeGen/lto-newpm-pipeline.c @@ -32,7 +32,6 @@ // CHECK-FULL-O0-NEXT: Running pass: AlwaysInlinerPass // CHECK-FULL-O0-NEXT: Running analysis: ProfileSummaryAnalysis // CHECK-FULL-O0-NEXT: Running pass: CoroConditionalWrapper -// CHECK-FULL-O0-NEXT: Running pass: AllocTokenPass // CHECK-FULL-O0-NEXT: Running pass: CanonicalizeAliasesPass // CHECK-FULL-O0-NEXT: Running pass: NameAnonGlobalPass // CHECK-FULL-O0-NEXT: Running pass: AnnotationRemarksPass @@ -47,7 +46,6 @@ // CHECK-THIN-O0-NEXT: Running pass: AlwaysInlinerPass // CHECK-THIN-O0-NEXT: Running analysis: ProfileSummaryAnalysis // CHECK-THIN-O0-NEXT: Running pass: CoroConditionalWrapper -// CHECK-THIN-O0-NEXT: Running pass: AllocTokenPass // CHECK-THIN-O0-NEXT: Running pass: CanonicalizeAliasesPass // CHECK-THIN-O0-NEXT: Running pass: NameAnonGlobalPass // CHECK-THIN-O0-NEXT: Running pass: AnnotationRemarksPass _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
