Skip to content

Commit

Permalink
Run Coverage pass before other *San passes under new pass manager, ro…
Browse files Browse the repository at this point in the history
…und 2

Summary:
This was attempted once before in https://reviews.llvm.org/D79698, but
was reverted due to the coverage pass running in the wrong part of the
pipeline. This commit puts it in the same place as the other sanitizers.

This changes PassBuilder.OptimizerLastEPCallbacks to work on a
ModulePassManager instead of a FunctionPassManager. That is because
SanitizerCoverage cannot (easily) be split into a module pass and a
function pass like some of the other sanitizers since in its current
implementation it conditionally inserts module constructors based on
whether or not it successfully modified functions.

This fixes compiler-rt/test/msan/coverage-levels.cpp under the new pass
manager (last check-msan test).

Currently sanitizers + LTO don't work together under the new pass
manager, so I removed tests that checked that this combination works for
sancov.

Subscribers: hiraditya, cfe-commits, llvm-commits

Tags: #clang, #llvm

Differential Revision: https://reviews.llvm.org/D80692
  • Loading branch information
aeubanks committed May 29, 2020
1 parent fd1c894 commit 1285e8b
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 28 deletions.
50 changes: 34 additions & 16 deletions clang/lib/CodeGen/BackendUtil.cpp
Expand Up @@ -32,6 +32,7 @@
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/ModuleSummaryIndex.h"
#include "llvm/IR/PassManager.h"
#include "llvm/IR/Verifier.h"
#include "llvm/LTO/LTOBackend.h"
#include "llvm/MC/MCAsmInfo.h"
Expand Down Expand Up @@ -1001,6 +1002,15 @@ static void addSanitizersAtO0(ModulePassManager &MPM,
const Triple &TargetTriple,
const LangOptions &LangOpts,
const CodeGenOptions &CodeGenOpts) {
if (CodeGenOpts.SanitizeCoverageType ||
CodeGenOpts.SanitizeCoverageIndirectCalls ||
CodeGenOpts.SanitizeCoverageTraceCmp) {
auto SancovOpts = getSancovOptsFromCGOpts(CodeGenOpts);
MPM.addPass(ModuleSanitizerCoveragePass(
SancovOpts, CodeGenOpts.SanitizeCoverageWhitelistFiles,
CodeGenOpts.SanitizeCoverageBlacklistFiles));
}

auto ASanPass = [&](SanitizerMask Mask, bool CompileKernel) {
MPM.addPass(RequireAnalysisPass<ASanGlobalsMetadataAnalysis, Module>());
bool Recover = CodeGenOpts.SanitizeRecover.has(Mask);
Expand Down Expand Up @@ -1249,6 +1259,20 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager(
[](FunctionPassManager &FPM, PassBuilder::OptimizationLevel Level) {
FPM.addPass(BoundsCheckingPass());
});

if (CodeGenOpts.SanitizeCoverageType ||
CodeGenOpts.SanitizeCoverageIndirectCalls ||
CodeGenOpts.SanitizeCoverageTraceCmp) {
PB.registerOptimizerLastEPCallback(
[this](ModulePassManager &MPM,
PassBuilder::OptimizationLevel Level) {
auto SancovOpts = getSancovOptsFromCGOpts(CodeGenOpts);
MPM.addPass(ModuleSanitizerCoveragePass(
SancovOpts, CodeGenOpts.SanitizeCoverageWhitelistFiles,
CodeGenOpts.SanitizeCoverageBlacklistFiles));
});
}

if (LangOpts.Sanitize.has(SanitizerKind::Memory)) {
int TrackOrigins = CodeGenOpts.SanitizeMemoryTrackOrigins;
bool Recover = CodeGenOpts.SanitizeRecover.has(SanitizerKind::Memory);
Expand All @@ -1257,17 +1281,19 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager(
MPM.addPass(MemorySanitizerPass({TrackOrigins, Recover, false}));
});
PB.registerOptimizerLastEPCallback(
[TrackOrigins, Recover](FunctionPassManager &FPM,
[TrackOrigins, Recover](ModulePassManager &MPM,
PassBuilder::OptimizationLevel Level) {
FPM.addPass(MemorySanitizerPass({TrackOrigins, Recover, false}));
MPM.addPass(createModuleToFunctionPassAdaptor(
MemorySanitizerPass({TrackOrigins, Recover, false})));
});
}
if (LangOpts.Sanitize.has(SanitizerKind::Thread)) {
PB.registerPipelineStartEPCallback(
[](ModulePassManager &MPM) { MPM.addPass(ThreadSanitizerPass()); });
PB.registerOptimizerLastEPCallback(
[](FunctionPassManager &FPM, PassBuilder::OptimizationLevel Level) {
FPM.addPass(ThreadSanitizerPass());
[](ModulePassManager &MPM, PassBuilder::OptimizationLevel Level) {
MPM.addPass(
createModuleToFunctionPassAdaptor(ThreadSanitizerPass()));
});
}
if (LangOpts.Sanitize.has(SanitizerKind::Address)) {
Expand All @@ -1278,10 +1304,11 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager(
bool Recover = CodeGenOpts.SanitizeRecover.has(SanitizerKind::Address);
bool UseAfterScope = CodeGenOpts.SanitizeAddressUseAfterScope;
PB.registerOptimizerLastEPCallback(
[Recover, UseAfterScope](FunctionPassManager &FPM,
[Recover, UseAfterScope](ModulePassManager &MPM,
PassBuilder::OptimizationLevel Level) {
FPM.addPass(AddressSanitizerPass(
/*CompileKernel=*/false, Recover, UseAfterScope));
MPM.addPass(
createModuleToFunctionPassAdaptor(AddressSanitizerPass(
/*CompileKernel=*/false, Recover, UseAfterScope)));
});
bool ModuleUseAfterScope = asanUseGlobalsGC(TargetTriple, CodeGenOpts);
bool UseOdrIndicator = CodeGenOpts.SanitizeAddressUseOdrIndicator;
Expand Down Expand Up @@ -1325,15 +1352,6 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager(
}
}

if (CodeGenOpts.SanitizeCoverageType ||
CodeGenOpts.SanitizeCoverageIndirectCalls ||
CodeGenOpts.SanitizeCoverageTraceCmp) {
auto SancovOpts = getSancovOptsFromCGOpts(CodeGenOpts);
MPM.addPass(ModuleSanitizerCoveragePass(
SancovOpts, CodeGenOpts.SanitizeCoverageWhitelistFiles,
CodeGenOpts.SanitizeCoverageBlacklistFiles));
}

if (LangOpts.Sanitize.has(SanitizerKind::HWAddress)) {
bool Recover = CodeGenOpts.SanitizeRecover.has(SanitizerKind::HWAddress);
MPM.addPass(HWAddressSanitizerPass(
Expand Down
8 changes: 2 additions & 6 deletions clang/test/CodeGen/sancov-new-pm.c
@@ -1,10 +1,6 @@
// Test that SanitizerCoverage works under the new pass manager.
// RUN: %clang -target x86_64-linux-gnu -fsanitize=fuzzer %s -fexperimental-new-pass-manager -S -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,CHECK-O0
// RUN: %clang -target x86_64-linux-gnu -fsanitize=fuzzer %s -fexperimental-new-pass-manager -O2 -S -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,CHECK-O2
// RUN: %clang -target x86_64-linux-gnu -fsanitize=fuzzer %s -fexperimental-new-pass-manager -flto -S -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,CHECK-O0
// RUN: %clang -target x86_64-linux-gnu -fsanitize=fuzzer %s -fexperimental-new-pass-manager -flto -O2 -S -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,CHECK-O2
// RUN: %clang -target x86_64-linux-gnu -fsanitize=fuzzer %s -fexperimental-new-pass-manager -flto=thin -S -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,CHECK-O0
// RUN: %clang -target x86_64-linux-gnu -fsanitize=fuzzer %s -fexperimental-new-pass-manager -flto=thin -O2 -S -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,CHECK-O2,CHECK-O2-THINLTO

extern void *memcpy(void *, const void *, unsigned long);
extern int printf(const char *restrict, ...);
Expand All @@ -29,10 +25,10 @@ int LLVMFuzzerTestOneInput(const unsigned char *data, unsigned long size) {
// CHECK-O0-DAG: declare void @__sanitizer_cov_trace_cmp2(i16 zeroext, i16 zeroext)
// CHECK-O0-DAG: declare void @__sanitizer_cov_trace_cmp4(i32 zeroext, i32 zeroext)
// CHECK-O0-DAG: declare void @__sanitizer_cov_trace_cmp8(i64, i64)
// CHECK-O2-THINLTO-NOT: declare void @__sanitizer_cov_trace_const_cmp1(i8 zeroext, i8 zeroext)
// CHECK-O2-NOT: declare void @__sanitizer_cov_trace_const_cmp1(i8 zeroext, i8 zeroext)
// CHECK-O0-DAG: declare void @__sanitizer_cov_trace_const_cmp2(i16 zeroext, i16 zeroext)
// CHECK-O0-DAG: declare void @__sanitizer_cov_trace_const_cmp4(i32 zeroext, i32 zeroext)
// CHECK-O2-THINLTO-NOT: declare void @__sanitizer_cov_trace_const_cmp8(i64, i64)
// CHECK-O2-NOT: declare void @__sanitizer_cov_trace_const_cmp8(i64, i64)
// CHECK-O0-DAG: declare void @__sanitizer_cov_trace_div4(i32 zeroext)
// CHECK-O0-DAG: declare void @__sanitizer_cov_trace_div8(i64)
// CHECK-O0-DAG: declare void @__sanitizer_cov_trace_gep(i64)
Expand Down
4 changes: 2 additions & 2 deletions llvm/include/llvm/Passes/PassBuilder.h
Expand Up @@ -600,7 +600,7 @@ class PassBuilder {
/// is not triggered at O0. Extensions to the O0 pipeline should append their
/// passes to the end of the overall pipeline.
void registerOptimizerLastEPCallback(
const std::function<void(FunctionPassManager &, OptimizationLevel)> &C) {
const std::function<void(ModulePassManager &, OptimizationLevel)> &C) {
OptimizerLastEPCallbacks.push_back(C);
}

Expand Down Expand Up @@ -728,7 +728,7 @@ class PassBuilder {
CGSCCOptimizerLateEPCallbacks;
SmallVector<std::function<void(FunctionPassManager &, OptimizationLevel)>, 2>
VectorizerStartEPCallbacks;
SmallVector<std::function<void(FunctionPassManager &, OptimizationLevel)>, 2>
SmallVector<std::function<void(ModulePassManager &, OptimizationLevel)>, 2>
OptimizerLastEPCallbacks;
// Module callbacks
SmallVector<std::function<void(ModulePassManager &)>, 2>
Expand Down
6 changes: 3 additions & 3 deletions llvm/lib/Passes/PassBuilder.cpp
Expand Up @@ -1073,12 +1073,12 @@ ModulePassManager PassBuilder::buildModuleOptimizationPipeline(
if (PTO.Coroutines)
OptimizePM.addPass(CoroCleanupPass());

for (auto &C : OptimizerLastEPCallbacks)
C(OptimizePM, Level);

// Add the core optimizing pipeline.
MPM.addPass(createModuleToFunctionPassAdaptor(std::move(OptimizePM)));

for (auto &C : OptimizerLastEPCallbacks)
C(MPM, Level);

if (PTO.CallGraphProfile)
MPM.addPass(CGProfilePass());

Expand Down
2 changes: 1 addition & 1 deletion llvm/tools/opt/NewPMDriver.cpp
Expand Up @@ -194,7 +194,7 @@ static void registerEPCallbacks(PassBuilder &PB, bool VerifyEachPass,
});
if (tryParsePipelineText<FunctionPassManager>(PB, OptimizerLastEPPipeline))
PB.registerOptimizerLastEPCallback(
[&PB, VerifyEachPass, DebugLogging](FunctionPassManager &PM,
[&PB, VerifyEachPass, DebugLogging](ModulePassManager &PM,
PassBuilder::OptimizationLevel) {
ExitOnError Err("Unable to parse OptimizerLastEP pipeline: ");
Err(PB.parsePassPipeline(PM, OptimizerLastEPPipeline, VerifyEachPass,
Expand Down

0 comments on commit 1285e8b

Please sign in to comment.