xref: /llvm-project/llvm/lib/CodeGen/MIRFSDiscriminator.cpp (revision 2d854dd3e7c5a86ec5c37347ab326b8fa578d938)
1886629a8SRong Xu //===-------- MIRFSDiscriminator.cpp: Flow Sensitive Discriminator --------===//
2886629a8SRong Xu //
3886629a8SRong Xu // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4886629a8SRong Xu // See https://llvm.org/LICENSE.txt for license information.
5886629a8SRong Xu // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6886629a8SRong Xu //
7886629a8SRong Xu //===----------------------------------------------------------------------===//
8886629a8SRong Xu //
9886629a8SRong Xu // This file provides the implementation of a machine pass that adds the flow
10886629a8SRong Xu // sensitive discriminator to the instruction debug information.
11886629a8SRong Xu //
12886629a8SRong Xu //===----------------------------------------------------------------------===//
13886629a8SRong Xu 
14886629a8SRong Xu #include "llvm/CodeGen/MIRFSDiscriminator.h"
15886629a8SRong Xu #include "llvm/ADT/DenseMap.h"
16886629a8SRong Xu #include "llvm/ADT/DenseSet.h"
17886629a8SRong Xu #include "llvm/Analysis/BlockFrequencyInfoImpl.h"
18989f1c72Sserge-sans-paille #include "llvm/CodeGen/Passes.h"
19989f1c72Sserge-sans-paille #include "llvm/IR/DebugInfoMetadata.h"
20886629a8SRong Xu #include "llvm/IR/Function.h"
215b461d5eSHongtao Yu #include "llvm/IR/Module.h"
225b461d5eSHongtao Yu #include "llvm/IR/PseudoProbe.h"
23989f1c72Sserge-sans-paille #include "llvm/InitializePasses.h"
24886629a8SRong Xu #include "llvm/Support/CommandLine.h"
25886629a8SRong Xu #include "llvm/Support/Debug.h"
26886629a8SRong Xu #include "llvm/Support/raw_ostream.h"
27ebe09e2aSRong Xu #include "llvm/Support/xxhash.h"
2882a0bb1aSRong Xu #include "llvm/Transforms/Utils/SampleProfileLoaderBaseUtil.h"
29886629a8SRong Xu 
30886629a8SRong Xu using namespace llvm;
316745ffe4SRong Xu using namespace sampleprof;
3282a0bb1aSRong Xu using namespace sampleprofutil;
33886629a8SRong Xu 
34886629a8SRong Xu #define DEBUG_TYPE "mirfs-discriminators"
35886629a8SRong Xu 
36ebe09e2aSRong Xu // TODO(xur): Remove this option and related code once we make true as the
37ebe09e2aSRong Xu // default.
38*2d854dd3SFangrui Song namespace llvm {
39ebe09e2aSRong Xu cl::opt<bool> ImprovedFSDiscriminator(
40ebe09e2aSRong Xu     "improved-fs-discriminator", cl::Hidden, cl::init(false),
41ebe09e2aSRong Xu     cl::desc("New FS discriminators encoding (incompatible with the original "
42ebe09e2aSRong Xu              "encoding)"));
43*2d854dd3SFangrui Song }
44ebe09e2aSRong Xu 
45886629a8SRong Xu char MIRAddFSDiscriminators::ID = 0;
46886629a8SRong Xu 
47886629a8SRong Xu INITIALIZE_PASS(MIRAddFSDiscriminators, DEBUG_TYPE,
48886629a8SRong Xu                 "Add MIR Flow Sensitive Discriminators",
49886629a8SRong Xu                 /* cfg = */ false, /* is_analysis = */ false)
50886629a8SRong Xu 
51886629a8SRong Xu char &llvm::MIRAddFSDiscriminatorsID = MIRAddFSDiscriminators::ID;
52886629a8SRong Xu 
createMIRAddFSDiscriminatorsPass(FSDiscriminatorPass P)536745ffe4SRong Xu FunctionPass *llvm::createMIRAddFSDiscriminatorsPass(FSDiscriminatorPass P) {
546745ffe4SRong Xu   return new MIRAddFSDiscriminators(P);
55886629a8SRong Xu }
56886629a8SRong Xu 
57ebe09e2aSRong Xu // TODO(xur): Remove this once we switch to ImprovedFSDiscriminator.
58886629a8SRong Xu // Compute a hash value using debug line number, and the line numbers from the
59886629a8SRong Xu // inline stack.
getCallStackHashV0(const MachineBasicBlock & BB,const MachineInstr & MI,const DILocation * DIL)60ebe09e2aSRong Xu static uint64_t getCallStackHashV0(const MachineBasicBlock &BB,
61886629a8SRong Xu                                    const MachineInstr &MI,
62886629a8SRong Xu                                    const DILocation *DIL) {
6360a097e5SRong Xu   auto updateHash = [](const StringRef &Str) -> uint64_t {
6460a097e5SRong Xu     if (Str.empty())
6560a097e5SRong Xu       return 0;
6660a097e5SRong Xu     return MD5Hash(Str);
6760a097e5SRong Xu   };
6860a097e5SRong Xu   uint64_t Ret = updateHash(std::to_string(DIL->getLine()));
6960a097e5SRong Xu   Ret ^= updateHash(BB.getName());
7060a097e5SRong Xu   Ret ^= updateHash(DIL->getScope()->getSubprogram()->getLinkageName());
71886629a8SRong Xu   for (DIL = DIL->getInlinedAt(); DIL; DIL = DIL->getInlinedAt()) {
7260a097e5SRong Xu     Ret ^= updateHash(std::to_string(DIL->getLine()));
7360a097e5SRong Xu     Ret ^= updateHash(DIL->getScope()->getSubprogram()->getLinkageName());
74886629a8SRong Xu   }
75886629a8SRong Xu   return Ret;
76886629a8SRong Xu }
77886629a8SRong Xu 
getCallStackHash(const DILocation * DIL)78ebe09e2aSRong Xu static uint64_t getCallStackHash(const DILocation *DIL) {
79ebe09e2aSRong Xu   auto hashCombine = [](const uint64_t Seed, const uint64_t Val) {
80ebe09e2aSRong Xu     std::hash<uint64_t> Hasher;
81ebe09e2aSRong Xu     return Seed ^ (Hasher(Val) + 0x9e3779b9 + (Seed << 6) + (Seed >> 2));
82ebe09e2aSRong Xu   };
83ebe09e2aSRong Xu   uint64_t Ret = 0;
84ebe09e2aSRong Xu   for (DIL = DIL->getInlinedAt(); DIL; DIL = DIL->getInlinedAt()) {
8530e753ddSFangrui Song     Ret = hashCombine(Ret, xxh3_64bits(ArrayRef<uint8_t>(DIL->getLine())));
8630e753ddSFangrui Song     Ret = hashCombine(Ret, xxh3_64bits(DIL->getSubprogramLinkageName()));
87ebe09e2aSRong Xu   }
88ebe09e2aSRong Xu   return Ret;
89ebe09e2aSRong Xu }
90ebe09e2aSRong Xu 
91886629a8SRong Xu // Traverse the CFG and assign FD discriminators. If two instructions
92886629a8SRong Xu // have the same lineno and discriminator, but residing in different BBs,
93886629a8SRong Xu // the latter instruction will get a new discriminator value. The new
94886629a8SRong Xu // discriminator keeps the existing discriminator value but sets new bits
95886629a8SRong Xu // b/w LowBit and HighBit.
runOnMachineFunction(MachineFunction & MF)96886629a8SRong Xu bool MIRAddFSDiscriminators::runOnMachineFunction(MachineFunction &MF) {
97886629a8SRong Xu   if (!EnableFSDiscriminator)
98886629a8SRong Xu     return false;
995b461d5eSHongtao Yu 
1005b461d5eSHongtao Yu   bool HasPseudoProbe = MF.getFunction().getParent()->getNamedMetadata(
1015b461d5eSHongtao Yu       PseudoProbeDescMetadataName);
1025b461d5eSHongtao Yu 
1035b461d5eSHongtao Yu   if (!HasPseudoProbe && !MF.getFunction().shouldEmitDebugInfoForProfiling())
104ccbbb4f6SRong Xu     return false;
105886629a8SRong Xu 
106886629a8SRong Xu   bool Changed = false;
107ebe09e2aSRong Xu   using LocationDiscriminator =
108ebe09e2aSRong Xu       std::tuple<StringRef, unsigned, unsigned, uint64_t>;
109886629a8SRong Xu   using BBSet = DenseSet<const MachineBasicBlock *>;
110886629a8SRong Xu   using LocationDiscriminatorBBMap = DenseMap<LocationDiscriminator, BBSet>;
111886629a8SRong Xu   using LocationDiscriminatorCurrPassMap =
112886629a8SRong Xu       DenseMap<LocationDiscriminator, unsigned>;
113886629a8SRong Xu 
114886629a8SRong Xu   LocationDiscriminatorBBMap LDBM;
115886629a8SRong Xu   LocationDiscriminatorCurrPassMap LDCM;
116886629a8SRong Xu 
117886629a8SRong Xu   // Mask of discriminators before this pass.
118ebe09e2aSRong Xu   // TODO(xur): simplify this once we switch to ImprovedFSDiscriminator.
119ebe09e2aSRong Xu   unsigned LowBitTemp = LowBit;
120ebe09e2aSRong Xu   assert(LowBit > 0 && "LowBit in FSDiscriminator cannot be 0");
121ebe09e2aSRong Xu   if (ImprovedFSDiscriminator)
122ebe09e2aSRong Xu     LowBitTemp -= 1;
123ebe09e2aSRong Xu   unsigned BitMaskBefore = getN1Bits(LowBitTemp);
124886629a8SRong Xu   // Mask of discriminators including this pass.
125886629a8SRong Xu   unsigned BitMaskNow = getN1Bits(HighBit);
126886629a8SRong Xu   // Mask of discriminators for bits specific to this pass.
127886629a8SRong Xu   unsigned BitMaskThisPass = BitMaskNow ^ BitMaskBefore;
128886629a8SRong Xu   unsigned NumNewD = 0;
129886629a8SRong Xu 
130886629a8SRong Xu   LLVM_DEBUG(dbgs() << "MIRAddFSDiscriminators working on Func: "
131ebe09e2aSRong Xu                     << MF.getFunction().getName() << " Highbit=" << HighBit
132ebe09e2aSRong Xu                     << "\n");
133ebe09e2aSRong Xu 
134886629a8SRong Xu   for (MachineBasicBlock &BB : MF) {
135886629a8SRong Xu     for (MachineInstr &I : BB) {
1365b461d5eSHongtao Yu       if (HasPseudoProbe) {
1375b461d5eSHongtao Yu         // Only assign discriminators to pseudo probe instructions. Call
1385b461d5eSHongtao Yu         // instructions are excluded since their dwarf discriminators are used
1395b461d5eSHongtao Yu         // for other purposes, i.e, storing probe ids.
1405b461d5eSHongtao Yu         if (!I.isPseudoProbe())
1415b461d5eSHongtao Yu           continue;
1425b461d5eSHongtao Yu       } else if (ImprovedFSDiscriminator && I.isMetaInstruction()) {
143ebe09e2aSRong Xu         continue;
144ebe09e2aSRong Xu       }
145886629a8SRong Xu       const DILocation *DIL = I.getDebugLoc().get();
146886629a8SRong Xu       if (!DIL)
147886629a8SRong Xu         continue;
1485b461d5eSHongtao Yu 
1495b461d5eSHongtao Yu       // Use the id of pseudo probe to compute the discriminator.
1505b461d5eSHongtao Yu       unsigned LineNo =
1515b461d5eSHongtao Yu           I.isPseudoProbe() ? I.getOperand(1).getImm() : DIL->getLine();
152886629a8SRong Xu       if (LineNo == 0)
153886629a8SRong Xu         continue;
154886629a8SRong Xu       unsigned Discriminator = DIL->getDiscriminator();
155d4d6b9a1SHongtao Yu       // Clean up discriminators for pseudo probes at the first FS discriminator
156d4d6b9a1SHongtao Yu       // pass as their discriminators should not ever be used.
157d4d6b9a1SHongtao Yu       if ((Pass == FSDiscriminatorPass::Pass1) && I.isPseudoProbe()) {
158d4d6b9a1SHongtao Yu         Discriminator = 0;
159d4d6b9a1SHongtao Yu         I.setDebugLoc(DIL->cloneWithDiscriminator(0));
160d4d6b9a1SHongtao Yu       }
161ebe09e2aSRong Xu       uint64_t CallStackHashVal = 0;
162ebe09e2aSRong Xu       if (ImprovedFSDiscriminator)
163ebe09e2aSRong Xu         CallStackHashVal = getCallStackHash(DIL);
164ebe09e2aSRong Xu 
165ebe09e2aSRong Xu       LocationDiscriminator LD{DIL->getFilename(), LineNo, Discriminator,
166ebe09e2aSRong Xu                                CallStackHashVal};
167886629a8SRong Xu       auto &BBMap = LDBM[LD];
168886629a8SRong Xu       auto R = BBMap.insert(&BB);
169886629a8SRong Xu       if (BBMap.size() == 1)
170886629a8SRong Xu         continue;
171886629a8SRong Xu 
172886629a8SRong Xu       unsigned DiscriminatorCurrPass;
173886629a8SRong Xu       DiscriminatorCurrPass = R.second ? ++LDCM[LD] : LDCM[LD];
174886629a8SRong Xu       DiscriminatorCurrPass = DiscriminatorCurrPass << LowBit;
175ebe09e2aSRong Xu       if (!ImprovedFSDiscriminator)
176ebe09e2aSRong Xu         DiscriminatorCurrPass += getCallStackHashV0(BB, I, DIL);
177886629a8SRong Xu       DiscriminatorCurrPass &= BitMaskThisPass;
178886629a8SRong Xu       unsigned NewD = Discriminator | DiscriminatorCurrPass;
179886629a8SRong Xu       const auto *const NewDIL = DIL->cloneWithDiscriminator(NewD);
180886629a8SRong Xu       if (!NewDIL) {
181886629a8SRong Xu         LLVM_DEBUG(dbgs() << "Could not encode discriminator: "
182886629a8SRong Xu                           << DIL->getFilename() << ":" << DIL->getLine() << ":"
183886629a8SRong Xu                           << DIL->getColumn() << ":" << Discriminator << " "
184886629a8SRong Xu                           << I << "\n");
185886629a8SRong Xu         continue;
186886629a8SRong Xu       }
187886629a8SRong Xu 
188886629a8SRong Xu       I.setDebugLoc(NewDIL);
189886629a8SRong Xu       NumNewD++;
190886629a8SRong Xu       LLVM_DEBUG(dbgs() << DIL->getFilename() << ":" << DIL->getLine() << ":"
191886629a8SRong Xu                         << DIL->getColumn() << ": add FS discriminator, from "
192886629a8SRong Xu                         << Discriminator << " -> " << NewD << "\n");
193886629a8SRong Xu       Changed = true;
194886629a8SRong Xu     }
195886629a8SRong Xu   }
196886629a8SRong Xu 
197886629a8SRong Xu   if (Changed) {
19882a0bb1aSRong Xu     createFSDiscriminatorVariable(MF.getFunction().getParent());
199886629a8SRong Xu     LLVM_DEBUG(dbgs() << "Num of FS Discriminators: " << NumNewD << "\n");
20046776f75SMartin Storsjö     (void) NumNewD;
201886629a8SRong Xu   }
202886629a8SRong Xu 
203886629a8SRong Xu   return Changed;
204886629a8SRong Xu }
205