Skip to content

Commit eaa71a9

Browse files
authored
[clang] Add optional pass to remove UBSAN traps using PGO (#84214)
With #83471 it reduces UBSAN overhead from 44% to 6%. Measured as "Geomean difference" on "test-suite/MultiSource/Benchmarks" with PGO build. On real large server binary we see 95% of code is still instrumented, with 10% -> 1.5% UBSAN overhead improvements. We can pass this test only with subset of UBSAN, so base overhead is smaller. We have followup patches to improve it even further.
1 parent 08a9207 commit eaa71a9

File tree

2 files changed

+36
-0
lines changed

2 files changed

+36
-0
lines changed

clang/lib/CodeGen/BackendUtil.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,15 @@
7676
#include "llvm/Transforms/Instrumentation/MemProfiler.h"
7777
#include "llvm/Transforms/Instrumentation/MemorySanitizer.h"
7878
#include "llvm/Transforms/Instrumentation/PGOInstrumentation.h"
79+
#include "llvm/Transforms/Instrumentation/RemoveTrapsPass.h"
7980
#include "llvm/Transforms/Instrumentation/SanitizerBinaryMetadata.h"
8081
#include "llvm/Transforms/Instrumentation/SanitizerCoverage.h"
8182
#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
8283
#include "llvm/Transforms/ObjCARC.h"
8384
#include "llvm/Transforms/Scalar/EarlyCSE.h"
8485
#include "llvm/Transforms/Scalar/GVN.h"
8586
#include "llvm/Transforms/Scalar/JumpThreading.h"
87+
#include "llvm/Transforms/Scalar/SimplifyCFG.h"
8688
#include "llvm/Transforms/Utils/Debugify.h"
8789
#include "llvm/Transforms/Utils/EntryExitInstrumenter.h"
8890
#include "llvm/Transforms/Utils/ModuleUtils.h"
@@ -98,6 +100,10 @@ using namespace llvm;
98100
namespace llvm {
99101
extern cl::opt<bool> PrintPipelinePasses;
100102

103+
cl::opt<bool> ClRemoveTraps("clang-remove-traps", cl::Optional,
104+
cl::desc("Insert remove-traps pass."),
105+
cl::init(false));
106+
101107
// Experiment to move sanitizers earlier.
102108
static cl::opt<bool> ClSanitizeOnOptimizerEarlyEP(
103109
"sanitizer-early-opt-ep", cl::Optional,
@@ -744,6 +750,21 @@ static void addSanitizers(const Triple &TargetTriple,
744750
// LastEP does not need GlobalsAA.
745751
PB.registerOptimizerLastEPCallback(SanitizersCallback);
746752
}
753+
754+
if (ClRemoveTraps) {
755+
// We can optimize after inliner, and PGO profile matching. The hook below
756+
// is called at the end `buildFunctionSimplificationPipeline`, which called
757+
// from `buildInlinerPipeline`, which called after profile matching.
758+
PB.registerScalarOptimizerLateEPCallback(
759+
[](FunctionPassManager &FPM, OptimizationLevel Level) {
760+
// RemoveTrapsPass expects trap blocks preceded by conditional
761+
// branches, which usually is not the case without SimplifyCFG.
762+
// TODO: Remove `SimplifyCFGPass` after switching to dedicated
763+
// intrinsic.
764+
FPM.addPass(SimplifyCFGPass());
765+
FPM.addPass(RemoveTrapsPass());
766+
});
767+
}
747768
}
748769

749770
void EmitAssemblyHelper::RunOptimizationPipeline(

clang/test/CodeGen/remote-traps.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// RUN: %clang_cc1 -O1 -emit-llvm -fsanitize=signed-integer-overflow -fsanitize-trap=signed-integer-overflow %s -o - | FileCheck %s
2+
// RUN: %clang_cc1 -O1 -emit-llvm -fsanitize=signed-integer-overflow -fsanitize-trap=signed-integer-overflow -mllvm -clang-remove-traps -mllvm -remove-traps-random-rate=1 %s -o - | FileCheck %s --implicit-check-not="call void @llvm.ubsantrap" --check-prefixes=REMOVE
3+
4+
int f(int x) {
5+
return x + 123;
6+
}
7+
8+
// CHECK-LABEL: define dso_local noundef i32 @f(
9+
// CHECK: call { i32, i1 } @llvm.sadd.with.overflow.i32(
10+
// CHECK: trap:
11+
// CHECK-NEXT: call void @llvm.ubsantrap(i8 0)
12+
// CHECK-NEXT: unreachable
13+
14+
// REMOVE-LABEL: define dso_local noundef i32 @f(
15+
// REMOVE: call { i32, i1 } @llvm.sadd.with.overflow.i32(

0 commit comments

Comments
 (0)