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;
RemarkInfoRemarkInfo48*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
emitRemark(IntrinsicInst * II,OptimizationRemarkEmitter & ORE,bool Removed)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
removeUbsanTraps(Function & F,const BlockFrequencyInfo & BFI,const ProfileSummaryInfo * PSI,OptimizationRemarkEmitter & ORE)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
run(Function & F,FunctionAnalysisManager & AM)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
IsRequested()144*0fca6ea1SDimitry Andric bool LowerAllowCheckPass::IsRequested() {
145*0fca6ea1SDimitry Andric return RandomRate.getNumOccurrences() ||
146*0fca6ea1SDimitry Andric HotPercentileCutoff.getNumOccurrences();
147*0fca6ea1SDimitry Andric }
148