//===--- MisExpect.cpp - Check the use of llvm.expect with PGO data -------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This contains code to emit warnings for potentially incorrect usage of the // llvm.expect intrinsic. This utility extracts the threshold values from // metadata associated with the instrumented Branch or Switch instruction. The // threshold values are then used to determine if a warning should be emmited. // // MisExpect's implementation relies on two assumptions about how branch weights // are managed in LLVM. // // 1) Frontend profiling weights are always in place before llvm.expect is // lowered in LowerExpectIntrinsic.cpp. Frontend based instrumentation therefore // needs to extract the branch weights and then compare them to the weights // being added by the llvm.expect intrinsic lowering. // // 2) Sampling and IR based profiles will *only* have branch weight metadata // before profiling data is consulted if they are from a lowered llvm.expect // intrinsic. These profiles thus always extract the expected weights and then // compare them to the weights collected during profiling to determine if a // diagnostic message is warranted. // //===----------------------------------------------------------------------===// #include "llvm/Transforms/Utils/MisExpect.h" #include "llvm/ADT/Twine.h" #include "llvm/Analysis/OptimizationRemarkEmitter.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/ProfDataUtils.h" #include "llvm/Support/BranchProbability.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FormatVariadic.h" #include <algorithm> #include <cstdint> #include <functional> #include <numeric> #define DEBUG_TYPE … usingnamespacellvm; usingnamespacemisexpect; namespace llvm { // Command line option to enable/disable the warning when profile data suggests // a mismatch with the use of the llvm.expect intrinsic static cl::opt<bool> PGOWarnMisExpect( "pgo-warn-misexpect", cl::init(false), cl::Hidden, cl::desc("Use this option to turn on/off " "warnings about incorrect usage of llvm.expect intrinsics.")); // Command line option for setting the diagnostic tolerance threshold static cl::opt<uint32_t> MisExpectTolerance( "misexpect-tolerance", cl::init(0), cl::desc("Prevents emitting diagnostics when profile counts are " "within N% of the threshold..")); } // namespace llvm namespace { bool isMisExpectDiagEnabled(LLVMContext &Ctx) { … } uint32_t getMisExpectTolerance(LLVMContext &Ctx) { … } Instruction *getInstCondition(Instruction *I) { … } void emitMisexpectDiagnostic(Instruction *I, LLVMContext &Ctx, uint64_t ProfCount, uint64_t TotalCount) { … } } // namespace namespace llvm { namespace misexpect { void verifyMisExpect(Instruction &I, ArrayRef<uint32_t> RealWeights, ArrayRef<uint32_t> ExpectedWeights) { … } void checkBackendInstrumentation(Instruction &I, const ArrayRef<uint32_t> RealWeights) { … } void checkFrontendInstrumentation(Instruction &I, const ArrayRef<uint32_t> ExpectedWeights) { … } void checkExpectAnnotations(Instruction &I, const ArrayRef<uint32_t> ExistingWeights, bool IsFrontend) { … } } // namespace misexpect } // namespace llvm #undef DEBUG_TYPE