Files
clang-p2996/llvm/lib/Transforms/Instrumentation/RemoveTrapsPass.cpp
Vitaly Buka a6a6fca791 [ubsan][pgo] Pass to remove ubsan checks based on profile data (#83471)
UBSAN checks can be too expensive to be used
in release binaries. However not all code affect
performace in the same way. Removing small
number of checks in hot code we can performance
loss, preserving most of the checks.
2024-03-07 10:52:43 -08:00

105 lines
3.3 KiB
C++

//===- RemoveTrapsPass.cpp --------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "llvm/Transforms/Instrumentation/RemoveTrapsPass.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/ProfileSummaryInfo.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/Support/RandomNumberGenerator.h"
#include <memory>
#include <random>
using namespace llvm;
#define DEBUG_TYPE "remove-traps"
static cl::opt<int> HotPercentileCutoff(
"remove-traps-percentile-cutoff-hot", cl::init(0),
cl::desc("Alternative hot percentile cuttoff. By default "
"`-profile-summary-cutoff-hot` is used."));
static cl::opt<float>
RandomRate("remove-traps-random-rate", cl::init(0.0),
cl::desc("Probability value in the range [0.0, 1.0] of "
"unconditional pseudo-random checks removal."));
STATISTIC(NumChecksTotal, "Number of checks");
STATISTIC(NumChecksRemoved, "Number of removed checks");
static bool removeUbsanTraps(Function &F, const BlockFrequencyInfo &BFI,
const ProfileSummaryInfo *PSI) {
SmallVector<IntrinsicInst *, 16> Remove;
std::unique_ptr<RandomNumberGenerator> Rng;
auto ShouldRemove = [&](bool IsHot) {
if (!RandomRate.getNumOccurrences())
return IsHot;
if (!Rng)
Rng = F.getParent()->createRNG(F.getName());
std::bernoulli_distribution D(RandomRate);
return D(*Rng);
};
for (BasicBlock &BB : F) {
for (Instruction &I : BB) {
IntrinsicInst *II = dyn_cast<IntrinsicInst>(&I);
if (!II)
continue;
auto ID = II->getIntrinsicID();
switch (ID) {
case Intrinsic::ubsantrap: {
++NumChecksTotal;
bool IsHot = false;
if (PSI) {
uint64_t Count = 0;
for (const auto *PR : predecessors(&BB))
Count += BFI.getBlockProfileCount(PR).value_or(0);
IsHot =
HotPercentileCutoff.getNumOccurrences()
? (HotPercentileCutoff > 0 &&
PSI->isHotCountNthPercentile(HotPercentileCutoff, Count))
: PSI->isHotCount(Count);
}
if (ShouldRemove(IsHot)) {
Remove.push_back(II);
++NumChecksRemoved;
}
break;
}
default:
break;
}
}
}
for (IntrinsicInst *I : Remove)
I->eraseFromParent();
return !Remove.empty();
}
PreservedAnalyses RemoveTrapsPass::run(Function &F,
FunctionAnalysisManager &AM) {
if (F.isDeclaration())
return PreservedAnalyses::all();
auto &MAMProxy = AM.getResult<ModuleAnalysisManagerFunctionProxy>(F);
ProfileSummaryInfo *PSI =
MAMProxy.getCachedResult<ProfileSummaryAnalysis>(*F.getParent());
BlockFrequencyInfo &BFI = AM.getResult<BlockFrequencyAnalysis>(F);
return removeUbsanTraps(F, BFI, PSI) ? PreservedAnalyses::none()
: PreservedAnalyses::all();
}