brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.4 KiB · 2486e77 Raw
199 lines · cpp
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-exception6//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/StringExtras.h"14#include "llvm/ADT/StringRef.h"15#include "llvm/Analysis/OptimizationRemarkEmitter.h"16#include "llvm/Analysis/ProfileSummaryInfo.h"17#include "llvm/IR/Constants.h"18#include "llvm/IR/DiagnosticInfo.h"19#include "llvm/IR/InstIterator.h"20#include "llvm/IR/Instructions.h"21#include "llvm/IR/IntrinsicInst.h"22#include "llvm/IR/Intrinsics.h"23#include "llvm/IR/Metadata.h"24#include "llvm/IR/Module.h"25#include "llvm/Support/Debug.h"26#include "llvm/Support/RandomNumberGenerator.h"27#include <memory>28#include <random>29 30using namespace llvm;31 32#define DEBUG_TYPE "lower-allow-check"33 34static cl::opt<int>35    HotPercentileCutoff("lower-allow-check-percentile-cutoff-hot",36                        cl::desc("Hot percentile cutoff."));37 38static cl::opt<float>39    RandomRate("lower-allow-check-random-rate",40               cl::desc("Probability value in the range [0.0, 1.0] of "41                        "unconditional pseudo-random checks."));42 43STATISTIC(NumChecksTotal, "Number of checks");44STATISTIC(NumChecksRemoved, "Number of removed checks");45 46struct RemarkInfo {47  ore::NV Kind;48  ore::NV F;49  ore::NV BB;50  explicit RemarkInfo(IntrinsicInst *II)51      : Kind("Kind", II->getArgOperand(0)),52        F("Function", II->getParent()->getParent()),53        BB("Block", II->getParent()->getName()) {}54};55 56static void emitRemark(IntrinsicInst *II, OptimizationRemarkEmitter &ORE,57                       bool Removed) {58  if (Removed) {59    ORE.emit([&]() {60      RemarkInfo Info(II);61      return OptimizationRemark(DEBUG_TYPE, "Removed", II)62             << "Removed check: Kind=" << Info.Kind << " F=" << Info.F63             << " BB=" << Info.BB;64    });65  } else {66    ORE.emit([&]() {67      RemarkInfo Info(II);68      return OptimizationRemarkMissed(DEBUG_TYPE, "Allowed", II)69             << "Allowed check: Kind=" << Info.Kind << " F=" << Info.F70             << " BB=" << Info.BB;71    });72  }73}74 75static bool lowerAllowChecks(Function &F, const BlockFrequencyInfo &BFI,76                             const ProfileSummaryInfo *PSI,77                             OptimizationRemarkEmitter &ORE,78                             const LowerAllowCheckPass::Options &Opts) {79  SmallVector<std::pair<IntrinsicInst *, bool>, 16> ReplaceWithValue;80  std::unique_ptr<RandomNumberGenerator> Rng;81 82  auto GetRng = [&]() -> RandomNumberGenerator & {83    if (!Rng)84      Rng = F.getParent()->createRNG(F.getName());85    return *Rng;86  };87 88  auto GetCutoff = [&](const IntrinsicInst *II) -> unsigned {89    if (HotPercentileCutoff.getNumOccurrences())90      return HotPercentileCutoff;91    else if (II->getIntrinsicID() == Intrinsic::allow_ubsan_check) {92      auto *Kind = cast<ConstantInt>(II->getArgOperand(0));93      if (Kind->getZExtValue() < Opts.cutoffs.size())94        return Opts.cutoffs[Kind->getZExtValue()];95    } else if (II->getIntrinsicID() == Intrinsic::allow_runtime_check) {96      return Opts.runtime_check;97    }98 99    return 0;100  };101 102  auto ShouldRemoveHot = [&](const BasicBlock &BB, unsigned int cutoff) {103    return (cutoff == 1000000) ||104           (PSI && PSI->isHotCountNthPercentile(105                       cutoff, BFI.getBlockProfileCount(&BB).value_or(0)));106  };107 108  auto ShouldRemoveRandom = [&]() {109    return RandomRate.getNumOccurrences() &&110           !std::bernoulli_distribution(RandomRate)(GetRng());111  };112 113  auto ShouldRemove = [&](const IntrinsicInst *II) {114    unsigned int cutoff = GetCutoff(II);115    return ShouldRemoveRandom() || ShouldRemoveHot(*(II->getParent()), cutoff);116  };117 118  for (Instruction &I : instructions(F)) {119    IntrinsicInst *II = dyn_cast<IntrinsicInst>(&I);120    if (!II)121      continue;122    auto ID = II->getIntrinsicID();123    switch (ID) {124    case Intrinsic::allow_ubsan_check:125    case Intrinsic::allow_runtime_check: {126      ++NumChecksTotal;127 128      bool ToRemove = ShouldRemove(II);129 130      ReplaceWithValue.push_back({131          II,132          ToRemove,133      });134      if (ToRemove)135        ++NumChecksRemoved;136      emitRemark(II, ORE, ToRemove);137      break;138    }139    default:140      break;141    }142  }143 144  for (auto [I, V] : ReplaceWithValue) {145    I->replaceAllUsesWith(ConstantInt::getBool(I->getType(), !V));146    I->eraseFromParent();147  }148 149  return !ReplaceWithValue.empty();150}151 152PreservedAnalyses LowerAllowCheckPass::run(Function &F,153                                           FunctionAnalysisManager &AM) {154  if (F.isDeclaration())155    return PreservedAnalyses::all();156  auto &MAMProxy = AM.getResult<ModuleAnalysisManagerFunctionProxy>(F);157  ProfileSummaryInfo *PSI =158      MAMProxy.getCachedResult<ProfileSummaryAnalysis>(*F.getParent());159  BlockFrequencyInfo &BFI = AM.getResult<BlockFrequencyAnalysis>(F);160  OptimizationRemarkEmitter &ORE =161      AM.getResult<OptimizationRemarkEmitterAnalysis>(F);162 163  return lowerAllowChecks(F, BFI, PSI, ORE, Opts)164             // We do not change the CFG, we only replace the intrinsics with165             // true or false.166             ? PreservedAnalyses::none().preserveSet<CFGAnalyses>()167             : PreservedAnalyses::all();168}169 170bool LowerAllowCheckPass::IsRequested() {171  return RandomRate.getNumOccurrences() ||172         HotPercentileCutoff.getNumOccurrences();173}174 175void LowerAllowCheckPass::printPipeline(176    raw_ostream &OS, function_ref<StringRef(StringRef)> MapClassName2PassName) {177  static_cast<PassInfoMixin<LowerAllowCheckPass> *>(this)->printPipeline(178      OS, MapClassName2PassName);179  OS << "<";180 181  // Format is <cutoffs[0,1,2]=70000;cutoffs[5,6,8]=90000>182  // but it's equally valid to specify183  //   cutoffs[0]=70000;cutoffs[1]=70000;cutoffs[2]=70000;cutoffs[5]=90000;...184  // and that's what we do here. It is verbose but valid and easy to verify185  // correctness.186  // TODO: print shorter output by combining adjacent runs, etc.187  int i = 0;188  ListSeparator LS(";");189  for (unsigned int cutoff : Opts.cutoffs) {190    if (cutoff > 0)191      OS << LS << "cutoffs[" << i << "]=" << cutoff;192    i++;193  }194  if (Opts.runtime_check)195    OS << LS << "runtime_check=" << Opts.runtime_check;196 197  OS << '>';198}199