xref: /freebsd-src/contrib/llvm-project/llvm/lib/Transforms/Instrumentation/LowerAllowCheckPass.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1*0fca6ea1SDimitry Andric //===- LowerAllowCheckPass.cpp ----------------------------------*- C++ -*-===//
2*0fca6ea1SDimitry Andric //
3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0fca6ea1SDimitry Andric //
7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
8*0fca6ea1SDimitry Andric 
9*0fca6ea1SDimitry Andric #include "llvm/Transforms/Instrumentation/LowerAllowCheckPass.h"
10*0fca6ea1SDimitry Andric 
11*0fca6ea1SDimitry Andric #include "llvm/ADT/SmallVector.h"
12*0fca6ea1SDimitry Andric #include "llvm/ADT/Statistic.h"
13*0fca6ea1SDimitry Andric #include "llvm/ADT/StringRef.h"
14*0fca6ea1SDimitry Andric #include "llvm/Analysis/OptimizationRemarkEmitter.h"
15*0fca6ea1SDimitry Andric #include "llvm/Analysis/ProfileSummaryInfo.h"
16*0fca6ea1SDimitry Andric #include "llvm/IR/Constant.h"
17*0fca6ea1SDimitry Andric #include "llvm/IR/Constants.h"
18*0fca6ea1SDimitry Andric #include "llvm/IR/DiagnosticInfo.h"
19*0fca6ea1SDimitry Andric #include "llvm/IR/Instructions.h"
20*0fca6ea1SDimitry Andric #include "llvm/IR/IntrinsicInst.h"
21*0fca6ea1SDimitry Andric #include "llvm/IR/Intrinsics.h"
22*0fca6ea1SDimitry Andric #include "llvm/IR/Metadata.h"
23*0fca6ea1SDimitry Andric #include "llvm/IR/Module.h"
24*0fca6ea1SDimitry Andric #include "llvm/Support/RandomNumberGenerator.h"
25*0fca6ea1SDimitry Andric #include <memory>
26*0fca6ea1SDimitry Andric #include <random>
27*0fca6ea1SDimitry Andric 
28*0fca6ea1SDimitry Andric using namespace llvm;
29*0fca6ea1SDimitry Andric 
30*0fca6ea1SDimitry Andric #define DEBUG_TYPE "lower-allow-check"
31*0fca6ea1SDimitry Andric 
32*0fca6ea1SDimitry Andric static cl::opt<int>
33*0fca6ea1SDimitry Andric     HotPercentileCutoff("lower-allow-check-percentile-cutoff-hot",
34*0fca6ea1SDimitry Andric                         cl::desc("Hot percentile cuttoff."));
35*0fca6ea1SDimitry Andric 
36*0fca6ea1SDimitry Andric static cl::opt<float>
37*0fca6ea1SDimitry Andric     RandomRate("lower-allow-check-random-rate",
38*0fca6ea1SDimitry Andric                cl::desc("Probability value in the range [0.0, 1.0] of "
39*0fca6ea1SDimitry Andric                         "unconditional pseudo-random checks."));
40*0fca6ea1SDimitry Andric 
41*0fca6ea1SDimitry Andric STATISTIC(NumChecksTotal, "Number of checks");
42*0fca6ea1SDimitry Andric STATISTIC(NumChecksRemoved, "Number of removed checks");
43*0fca6ea1SDimitry Andric 
44*0fca6ea1SDimitry Andric struct RemarkInfo {
45*0fca6ea1SDimitry Andric   ore::NV Kind;
46*0fca6ea1SDimitry Andric   ore::NV F;
47*0fca6ea1SDimitry Andric   ore::NV BB;
48*0fca6ea1SDimitry Andric   explicit RemarkInfo(IntrinsicInst *II)
49*0fca6ea1SDimitry Andric       : Kind("Kind", II->getArgOperand(0)),
50*0fca6ea1SDimitry Andric         F("Function", II->getParent()->getParent()),
51*0fca6ea1SDimitry Andric         BB("Block", II->getParent()->getName()) {}
52*0fca6ea1SDimitry Andric };
53*0fca6ea1SDimitry Andric 
54*0fca6ea1SDimitry Andric static void emitRemark(IntrinsicInst *II, OptimizationRemarkEmitter &ORE,
55*0fca6ea1SDimitry Andric                        bool Removed) {
56*0fca6ea1SDimitry Andric   if (Removed) {
57*0fca6ea1SDimitry Andric     ORE.emit([&]() {
58*0fca6ea1SDimitry Andric       RemarkInfo Info(II);
59*0fca6ea1SDimitry Andric       return OptimizationRemark(DEBUG_TYPE, "Removed", II)
60*0fca6ea1SDimitry Andric              << "Removed check: Kind=" << Info.Kind << " F=" << Info.F
61*0fca6ea1SDimitry Andric              << " BB=" << Info.BB;
62*0fca6ea1SDimitry Andric     });
63*0fca6ea1SDimitry Andric   } else {
64*0fca6ea1SDimitry Andric     ORE.emit([&]() {
65*0fca6ea1SDimitry Andric       RemarkInfo Info(II);
66*0fca6ea1SDimitry Andric       return OptimizationRemarkMissed(DEBUG_TYPE, "Allowed", II)
67*0fca6ea1SDimitry Andric              << "Allowed check: Kind=" << Info.Kind << " F=" << Info.F
68*0fca6ea1SDimitry Andric              << " BB=" << Info.BB;
69*0fca6ea1SDimitry Andric     });
70*0fca6ea1SDimitry Andric   }
71*0fca6ea1SDimitry Andric }
72*0fca6ea1SDimitry Andric 
73*0fca6ea1SDimitry Andric static bool removeUbsanTraps(Function &F, const BlockFrequencyInfo &BFI,
74*0fca6ea1SDimitry Andric                              const ProfileSummaryInfo *PSI,
75*0fca6ea1SDimitry Andric                              OptimizationRemarkEmitter &ORE) {
76*0fca6ea1SDimitry Andric   SmallVector<std::pair<IntrinsicInst *, bool>, 16> ReplaceWithValue;
77*0fca6ea1SDimitry Andric   std::unique_ptr<RandomNumberGenerator> Rng;
78*0fca6ea1SDimitry Andric 
79*0fca6ea1SDimitry Andric   auto ShouldRemove = [&](bool IsHot) {
80*0fca6ea1SDimitry Andric     if (!RandomRate.getNumOccurrences())
81*0fca6ea1SDimitry Andric       return IsHot;
82*0fca6ea1SDimitry Andric     if (!Rng)
83*0fca6ea1SDimitry Andric       Rng = F.getParent()->createRNG(F.getName());
84*0fca6ea1SDimitry Andric     std::bernoulli_distribution D(RandomRate);
85*0fca6ea1SDimitry Andric     return !D(*Rng);
86*0fca6ea1SDimitry Andric   };
87*0fca6ea1SDimitry Andric 
88*0fca6ea1SDimitry Andric   for (BasicBlock &BB : F) {
89*0fca6ea1SDimitry Andric     for (Instruction &I : BB) {
90*0fca6ea1SDimitry Andric       IntrinsicInst *II = dyn_cast<IntrinsicInst>(&I);
91*0fca6ea1SDimitry Andric       if (!II)
92*0fca6ea1SDimitry Andric         continue;
93*0fca6ea1SDimitry Andric       auto ID = II->getIntrinsicID();
94*0fca6ea1SDimitry Andric       switch (ID) {
95*0fca6ea1SDimitry Andric       case Intrinsic::allow_ubsan_check:
96*0fca6ea1SDimitry Andric       case Intrinsic::allow_runtime_check: {
97*0fca6ea1SDimitry Andric         ++NumChecksTotal;
98*0fca6ea1SDimitry Andric 
99*0fca6ea1SDimitry Andric         bool IsHot = false;
100*0fca6ea1SDimitry Andric         if (PSI) {
101*0fca6ea1SDimitry Andric           uint64_t Count = BFI.getBlockProfileCount(&BB).value_or(0);
102*0fca6ea1SDimitry Andric           IsHot = PSI->isHotCountNthPercentile(HotPercentileCutoff, Count);
103*0fca6ea1SDimitry Andric         }
104*0fca6ea1SDimitry Andric 
105*0fca6ea1SDimitry Andric         bool ToRemove = ShouldRemove(IsHot);
106*0fca6ea1SDimitry Andric         ReplaceWithValue.push_back({
107*0fca6ea1SDimitry Andric             II,
108*0fca6ea1SDimitry Andric             ToRemove,
109*0fca6ea1SDimitry Andric         });
110*0fca6ea1SDimitry Andric         if (ToRemove)
111*0fca6ea1SDimitry Andric           ++NumChecksRemoved;
112*0fca6ea1SDimitry Andric         emitRemark(II, ORE, ToRemove);
113*0fca6ea1SDimitry Andric         break;
114*0fca6ea1SDimitry Andric       }
115*0fca6ea1SDimitry Andric       default:
116*0fca6ea1SDimitry Andric         break;
117*0fca6ea1SDimitry Andric       }
118*0fca6ea1SDimitry Andric     }
119*0fca6ea1SDimitry Andric   }
120*0fca6ea1SDimitry Andric 
121*0fca6ea1SDimitry Andric   for (auto [I, V] : ReplaceWithValue) {
122*0fca6ea1SDimitry Andric     I->replaceAllUsesWith(ConstantInt::getBool(I->getType(), !V));
123*0fca6ea1SDimitry Andric     I->eraseFromParent();
124*0fca6ea1SDimitry Andric   }
125*0fca6ea1SDimitry Andric 
126*0fca6ea1SDimitry Andric   return !ReplaceWithValue.empty();
127*0fca6ea1SDimitry Andric }
128*0fca6ea1SDimitry Andric 
129*0fca6ea1SDimitry Andric PreservedAnalyses LowerAllowCheckPass::run(Function &F,
130*0fca6ea1SDimitry Andric                                            FunctionAnalysisManager &AM) {
131*0fca6ea1SDimitry Andric   if (F.isDeclaration())
132*0fca6ea1SDimitry Andric     return PreservedAnalyses::all();
133*0fca6ea1SDimitry Andric   auto &MAMProxy = AM.getResult<ModuleAnalysisManagerFunctionProxy>(F);
134*0fca6ea1SDimitry Andric   ProfileSummaryInfo *PSI =
135*0fca6ea1SDimitry Andric       MAMProxy.getCachedResult<ProfileSummaryAnalysis>(*F.getParent());
136*0fca6ea1SDimitry Andric   BlockFrequencyInfo &BFI = AM.getResult<BlockFrequencyAnalysis>(F);
137*0fca6ea1SDimitry Andric   OptimizationRemarkEmitter &ORE =
138*0fca6ea1SDimitry Andric       AM.getResult<OptimizationRemarkEmitterAnalysis>(F);
139*0fca6ea1SDimitry Andric 
140*0fca6ea1SDimitry Andric   return removeUbsanTraps(F, BFI, PSI, ORE) ? PreservedAnalyses::none()
141*0fca6ea1SDimitry Andric                                             : PreservedAnalyses::all();
142*0fca6ea1SDimitry Andric }
143*0fca6ea1SDimitry Andric 
144*0fca6ea1SDimitry Andric bool LowerAllowCheckPass::IsRequested() {
145*0fca6ea1SDimitry Andric   return RandomRate.getNumOccurrences() ||
146*0fca6ea1SDimitry Andric          HotPercentileCutoff.getNumOccurrences();
147*0fca6ea1SDimitry Andric }
148