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