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