xref: /freebsd-src/contrib/llvm-project/llvm/lib/CodeGen/MIRFSDiscriminator.cpp (revision fe6060f10f634930ff71b7c50291ddc610da2475)
1*fe6060f1SDimitry Andric //===-------- MIRFSDiscriminator.cpp: Flow Sensitive Discriminator --------===//
2*fe6060f1SDimitry Andric //
3*fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*fe6060f1SDimitry Andric //
7*fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
8*fe6060f1SDimitry Andric //
9*fe6060f1SDimitry Andric // This file provides the implementation of a machine pass that adds the flow
10*fe6060f1SDimitry Andric // sensitive discriminator to the instruction debug information.
11*fe6060f1SDimitry Andric //
12*fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
13*fe6060f1SDimitry Andric 
14*fe6060f1SDimitry Andric #include "llvm/CodeGen/MIRFSDiscriminator.h"
15*fe6060f1SDimitry Andric #include "llvm/ADT/DenseMap.h"
16*fe6060f1SDimitry Andric #include "llvm/ADT/DenseSet.h"
17*fe6060f1SDimitry Andric #include "llvm/Analysis/BlockFrequencyInfoImpl.h"
18*fe6060f1SDimitry Andric #include "llvm/IR/Function.h"
19*fe6060f1SDimitry Andric #include "llvm/Support/CommandLine.h"
20*fe6060f1SDimitry Andric #include "llvm/Support/Debug.h"
21*fe6060f1SDimitry Andric #include "llvm/Support/raw_ostream.h"
22*fe6060f1SDimitry Andric #include "llvm/Transforms/Utils/SampleProfileLoaderBaseUtil.h"
23*fe6060f1SDimitry Andric #include <unordered_map>
24*fe6060f1SDimitry Andric 
25*fe6060f1SDimitry Andric using namespace llvm;
26*fe6060f1SDimitry Andric using namespace sampleprof;
27*fe6060f1SDimitry Andric using namespace sampleprofutil;
28*fe6060f1SDimitry Andric 
29*fe6060f1SDimitry Andric #define DEBUG_TYPE "mirfs-discriminators"
30*fe6060f1SDimitry Andric 
31*fe6060f1SDimitry Andric char MIRAddFSDiscriminators::ID = 0;
32*fe6060f1SDimitry Andric 
33*fe6060f1SDimitry Andric INITIALIZE_PASS(MIRAddFSDiscriminators, DEBUG_TYPE,
34*fe6060f1SDimitry Andric                 "Add MIR Flow Sensitive Discriminators",
35*fe6060f1SDimitry Andric                 /* cfg = */ false, /* is_analysis = */ false)
36*fe6060f1SDimitry Andric 
37*fe6060f1SDimitry Andric char &llvm::MIRAddFSDiscriminatorsID = MIRAddFSDiscriminators::ID;
38*fe6060f1SDimitry Andric 
39*fe6060f1SDimitry Andric FunctionPass *llvm::createMIRAddFSDiscriminatorsPass(FSDiscriminatorPass P) {
40*fe6060f1SDimitry Andric   return new MIRAddFSDiscriminators(P);
41*fe6060f1SDimitry Andric }
42*fe6060f1SDimitry Andric 
43*fe6060f1SDimitry Andric // Compute a hash value using debug line number, and the line numbers from the
44*fe6060f1SDimitry Andric // inline stack.
45*fe6060f1SDimitry Andric static uint64_t getCallStackHash(const MachineBasicBlock &BB,
46*fe6060f1SDimitry Andric                                  const MachineInstr &MI,
47*fe6060f1SDimitry Andric                                  const DILocation *DIL) {
48*fe6060f1SDimitry Andric   auto updateHash = [](const StringRef &Str) -> uint64_t {
49*fe6060f1SDimitry Andric     if (Str.empty())
50*fe6060f1SDimitry Andric       return 0;
51*fe6060f1SDimitry Andric     return MD5Hash(Str);
52*fe6060f1SDimitry Andric   };
53*fe6060f1SDimitry Andric   uint64_t Ret = updateHash(std::to_string(DIL->getLine()));
54*fe6060f1SDimitry Andric   Ret ^= updateHash(BB.getName());
55*fe6060f1SDimitry Andric   Ret ^= updateHash(DIL->getScope()->getSubprogram()->getLinkageName());
56*fe6060f1SDimitry Andric   for (DIL = DIL->getInlinedAt(); DIL; DIL = DIL->getInlinedAt()) {
57*fe6060f1SDimitry Andric     Ret ^= updateHash(std::to_string(DIL->getLine()));
58*fe6060f1SDimitry Andric     Ret ^= updateHash(DIL->getScope()->getSubprogram()->getLinkageName());
59*fe6060f1SDimitry Andric   }
60*fe6060f1SDimitry Andric   return Ret;
61*fe6060f1SDimitry Andric }
62*fe6060f1SDimitry Andric 
63*fe6060f1SDimitry Andric // Traverse the CFG and assign FD discriminators. If two instructions
64*fe6060f1SDimitry Andric // have the same lineno and discriminator, but residing in different BBs,
65*fe6060f1SDimitry Andric // the latter instruction will get a new discriminator value. The new
66*fe6060f1SDimitry Andric // discriminator keeps the existing discriminator value but sets new bits
67*fe6060f1SDimitry Andric // b/w LowBit and HighBit.
68*fe6060f1SDimitry Andric bool MIRAddFSDiscriminators::runOnMachineFunction(MachineFunction &MF) {
69*fe6060f1SDimitry Andric   if (!EnableFSDiscriminator)
70*fe6060f1SDimitry Andric     return false;
71*fe6060f1SDimitry Andric 
72*fe6060f1SDimitry Andric   bool Changed = false;
73*fe6060f1SDimitry Andric   using LocationDiscriminator = std::tuple<StringRef, unsigned, unsigned>;
74*fe6060f1SDimitry Andric   using BBSet = DenseSet<const MachineBasicBlock *>;
75*fe6060f1SDimitry Andric   using LocationDiscriminatorBBMap = DenseMap<LocationDiscriminator, BBSet>;
76*fe6060f1SDimitry Andric   using LocationDiscriminatorCurrPassMap =
77*fe6060f1SDimitry Andric       DenseMap<LocationDiscriminator, unsigned>;
78*fe6060f1SDimitry Andric 
79*fe6060f1SDimitry Andric   LocationDiscriminatorBBMap LDBM;
80*fe6060f1SDimitry Andric   LocationDiscriminatorCurrPassMap LDCM;
81*fe6060f1SDimitry Andric 
82*fe6060f1SDimitry Andric   // Mask of discriminators before this pass.
83*fe6060f1SDimitry Andric   unsigned BitMaskBefore = getN1Bits(LowBit);
84*fe6060f1SDimitry Andric   // Mask of discriminators including this pass.
85*fe6060f1SDimitry Andric   unsigned BitMaskNow = getN1Bits(HighBit);
86*fe6060f1SDimitry Andric   // Mask of discriminators for bits specific to this pass.
87*fe6060f1SDimitry Andric   unsigned BitMaskThisPass = BitMaskNow ^ BitMaskBefore;
88*fe6060f1SDimitry Andric   unsigned NumNewD = 0;
89*fe6060f1SDimitry Andric 
90*fe6060f1SDimitry Andric   LLVM_DEBUG(dbgs() << "MIRAddFSDiscriminators working on Func: "
91*fe6060f1SDimitry Andric                     << MF.getFunction().getName() << "\n");
92*fe6060f1SDimitry Andric   for (MachineBasicBlock &BB : MF) {
93*fe6060f1SDimitry Andric     for (MachineInstr &I : BB) {
94*fe6060f1SDimitry Andric       const DILocation *DIL = I.getDebugLoc().get();
95*fe6060f1SDimitry Andric       if (!DIL)
96*fe6060f1SDimitry Andric         continue;
97*fe6060f1SDimitry Andric       unsigned LineNo = DIL->getLine();
98*fe6060f1SDimitry Andric       if (LineNo == 0)
99*fe6060f1SDimitry Andric         continue;
100*fe6060f1SDimitry Andric       unsigned Discriminator = DIL->getDiscriminator();
101*fe6060f1SDimitry Andric       LocationDiscriminator LD{DIL->getFilename(), LineNo, Discriminator};
102*fe6060f1SDimitry Andric       auto &BBMap = LDBM[LD];
103*fe6060f1SDimitry Andric       auto R = BBMap.insert(&BB);
104*fe6060f1SDimitry Andric       if (BBMap.size() == 1)
105*fe6060f1SDimitry Andric         continue;
106*fe6060f1SDimitry Andric 
107*fe6060f1SDimitry Andric       unsigned DiscriminatorCurrPass;
108*fe6060f1SDimitry Andric       DiscriminatorCurrPass = R.second ? ++LDCM[LD] : LDCM[LD];
109*fe6060f1SDimitry Andric       DiscriminatorCurrPass = DiscriminatorCurrPass << LowBit;
110*fe6060f1SDimitry Andric       DiscriminatorCurrPass += getCallStackHash(BB, I, DIL);
111*fe6060f1SDimitry Andric       DiscriminatorCurrPass &= BitMaskThisPass;
112*fe6060f1SDimitry Andric       unsigned NewD = Discriminator | DiscriminatorCurrPass;
113*fe6060f1SDimitry Andric       const auto *const NewDIL = DIL->cloneWithDiscriminator(NewD);
114*fe6060f1SDimitry Andric       if (!NewDIL) {
115*fe6060f1SDimitry Andric         LLVM_DEBUG(dbgs() << "Could not encode discriminator: "
116*fe6060f1SDimitry Andric                           << DIL->getFilename() << ":" << DIL->getLine() << ":"
117*fe6060f1SDimitry Andric                           << DIL->getColumn() << ":" << Discriminator << " "
118*fe6060f1SDimitry Andric                           << I << "\n");
119*fe6060f1SDimitry Andric         continue;
120*fe6060f1SDimitry Andric       }
121*fe6060f1SDimitry Andric 
122*fe6060f1SDimitry Andric       I.setDebugLoc(NewDIL);
123*fe6060f1SDimitry Andric       NumNewD++;
124*fe6060f1SDimitry Andric       LLVM_DEBUG(dbgs() << DIL->getFilename() << ":" << DIL->getLine() << ":"
125*fe6060f1SDimitry Andric                         << DIL->getColumn() << ": add FS discriminator, from "
126*fe6060f1SDimitry Andric                         << Discriminator << " -> " << NewD << "\n");
127*fe6060f1SDimitry Andric       Changed = true;
128*fe6060f1SDimitry Andric     }
129*fe6060f1SDimitry Andric   }
130*fe6060f1SDimitry Andric 
131*fe6060f1SDimitry Andric   if (Changed) {
132*fe6060f1SDimitry Andric     createFSDiscriminatorVariable(MF.getFunction().getParent());
133*fe6060f1SDimitry Andric     LLVM_DEBUG(dbgs() << "Num of FS Discriminators: " << NumNewD << "\n");
134*fe6060f1SDimitry Andric   }
135*fe6060f1SDimitry Andric 
136*fe6060f1SDimitry Andric   return Changed;
137*fe6060f1SDimitry Andric }
138