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"
21989f1c72Sserge-sans-paille #include "llvm/InitializePasses.h"
22886629a8SRong Xu #include "llvm/Support/CommandLine.h"
23886629a8SRong Xu #include "llvm/Support/Debug.h"
24886629a8SRong Xu #include "llvm/Support/raw_ostream.h"
2582a0bb1aSRong Xu #include "llvm/Transforms/Utils/SampleProfileLoaderBaseUtil.h"
26886629a8SRong Xu 
27886629a8SRong Xu using namespace llvm;
286745ffe4SRong Xu using namespace sampleprof;
2982a0bb1aSRong Xu using namespace sampleprofutil;
30886629a8SRong Xu 
31886629a8SRong Xu #define DEBUG_TYPE "mirfs-discriminators"
32886629a8SRong Xu 
33886629a8SRong Xu char MIRAddFSDiscriminators::ID = 0;
34886629a8SRong Xu 
35886629a8SRong Xu INITIALIZE_PASS(MIRAddFSDiscriminators, DEBUG_TYPE,
36886629a8SRong Xu                 "Add MIR Flow Sensitive Discriminators",
37886629a8SRong Xu                 /* cfg = */ false, /* is_analysis = */ false)
38886629a8SRong Xu 
39886629a8SRong Xu char &llvm::MIRAddFSDiscriminatorsID = MIRAddFSDiscriminators::ID;
40886629a8SRong Xu 
createMIRAddFSDiscriminatorsPass(FSDiscriminatorPass P)416745ffe4SRong Xu FunctionPass *llvm::createMIRAddFSDiscriminatorsPass(FSDiscriminatorPass P) {
426745ffe4SRong Xu   return new MIRAddFSDiscriminators(P);
43886629a8SRong Xu }
44886629a8SRong Xu 
45886629a8SRong Xu // Compute a hash value using debug line number, and the line numbers from the
46886629a8SRong Xu // inline stack.
getCallStackHash(const MachineBasicBlock & BB,const MachineInstr & MI,const DILocation * DIL)47886629a8SRong Xu static uint64_t getCallStackHash(const MachineBasicBlock &BB,
48886629a8SRong Xu                                  const MachineInstr &MI,
49886629a8SRong Xu                                  const DILocation *DIL) {
5060a097e5SRong Xu   auto updateHash = [](const StringRef &Str) -> uint64_t {
5160a097e5SRong Xu     if (Str.empty())
5260a097e5SRong Xu       return 0;
5360a097e5SRong Xu     return MD5Hash(Str);
5460a097e5SRong Xu   };
5560a097e5SRong Xu   uint64_t Ret = updateHash(std::to_string(DIL->getLine()));
5660a097e5SRong Xu   Ret ^= updateHash(BB.getName());
5760a097e5SRong Xu   Ret ^= updateHash(DIL->getScope()->getSubprogram()->getLinkageName());
58886629a8SRong Xu   for (DIL = DIL->getInlinedAt(); DIL; DIL = DIL->getInlinedAt()) {
5960a097e5SRong Xu     Ret ^= updateHash(std::to_string(DIL->getLine()));
6060a097e5SRong Xu     Ret ^= updateHash(DIL->getScope()->getSubprogram()->getLinkageName());
61886629a8SRong Xu   }
62886629a8SRong Xu   return Ret;
63886629a8SRong Xu }
64886629a8SRong Xu 
65886629a8SRong Xu // Traverse the CFG and assign FD discriminators. If two instructions
66886629a8SRong Xu // have the same lineno and discriminator, but residing in different BBs,
67886629a8SRong Xu // the latter instruction will get a new discriminator value. The new
68886629a8SRong Xu // discriminator keeps the existing discriminator value but sets new bits
69886629a8SRong Xu // b/w LowBit and HighBit.
runOnMachineFunction(MachineFunction & MF)70886629a8SRong Xu bool MIRAddFSDiscriminators::runOnMachineFunction(MachineFunction &MF) {
71886629a8SRong Xu   if (!EnableFSDiscriminator)
72886629a8SRong Xu     return false;
73ccbbb4f6SRong Xu   if (!MF.getFunction().isDebugInfoForProfiling())
74ccbbb4f6SRong Xu     return false;
75886629a8SRong Xu 
76886629a8SRong Xu   bool Changed = false;
77886629a8SRong Xu   using LocationDiscriminator = std::tuple<StringRef, unsigned, unsigned>;
78886629a8SRong Xu   using BBSet = DenseSet<const MachineBasicBlock *>;
79886629a8SRong Xu   using LocationDiscriminatorBBMap = DenseMap<LocationDiscriminator, BBSet>;
80886629a8SRong Xu   using LocationDiscriminatorCurrPassMap =
81886629a8SRong Xu       DenseMap<LocationDiscriminator, unsigned>;
82886629a8SRong Xu 
83886629a8SRong Xu   LocationDiscriminatorBBMap LDBM;
84886629a8SRong Xu   LocationDiscriminatorCurrPassMap LDCM;
85886629a8SRong Xu 
86886629a8SRong Xu   // Mask of discriminators before this pass.
87886629a8SRong Xu   unsigned BitMaskBefore = getN1Bits(LowBit);
88886629a8SRong Xu   // Mask of discriminators including this pass.
89886629a8SRong Xu   unsigned BitMaskNow = getN1Bits(HighBit);
90886629a8SRong Xu   // Mask of discriminators for bits specific to this pass.
91886629a8SRong Xu   unsigned BitMaskThisPass = BitMaskNow ^ BitMaskBefore;
92886629a8SRong Xu   unsigned NumNewD = 0;
93886629a8SRong Xu 
94886629a8SRong Xu   LLVM_DEBUG(dbgs() << "MIRAddFSDiscriminators working on Func: "
95886629a8SRong Xu                     << MF.getFunction().getName() << "\n");
96886629a8SRong Xu   for (MachineBasicBlock &BB : MF) {
97886629a8SRong Xu     for (MachineInstr &I : BB) {
98886629a8SRong Xu       const DILocation *DIL = I.getDebugLoc().get();
99886629a8SRong Xu       if (!DIL)
100886629a8SRong Xu         continue;
101886629a8SRong Xu       unsigned LineNo = DIL->getLine();
102886629a8SRong Xu       if (LineNo == 0)
103886629a8SRong Xu         continue;
104886629a8SRong Xu       unsigned Discriminator = DIL->getDiscriminator();
105a32e39a7SRong Xu       LocationDiscriminator LD{DIL->getFilename(), LineNo, Discriminator};
106886629a8SRong Xu       auto &BBMap = LDBM[LD];
107886629a8SRong Xu       auto R = BBMap.insert(&BB);
108886629a8SRong Xu       if (BBMap.size() == 1)
109886629a8SRong Xu         continue;
110886629a8SRong Xu 
111886629a8SRong Xu       unsigned DiscriminatorCurrPass;
112886629a8SRong Xu       DiscriminatorCurrPass = R.second ? ++LDCM[LD] : LDCM[LD];
113886629a8SRong Xu       DiscriminatorCurrPass = DiscriminatorCurrPass << LowBit;
114886629a8SRong Xu       DiscriminatorCurrPass += getCallStackHash(BB, I, DIL);
115886629a8SRong Xu       DiscriminatorCurrPass &= BitMaskThisPass;
116886629a8SRong Xu       unsigned NewD = Discriminator | DiscriminatorCurrPass;
117886629a8SRong Xu       const auto *const NewDIL = DIL->cloneWithDiscriminator(NewD);
118886629a8SRong Xu       if (!NewDIL) {
119886629a8SRong Xu         LLVM_DEBUG(dbgs() << "Could not encode discriminator: "
120886629a8SRong Xu                           << DIL->getFilename() << ":" << DIL->getLine() << ":"
121886629a8SRong Xu                           << DIL->getColumn() << ":" << Discriminator << " "
122886629a8SRong Xu                           << I << "\n");
123886629a8SRong Xu         continue;
124886629a8SRong Xu       }
125886629a8SRong Xu 
126886629a8SRong Xu       I.setDebugLoc(NewDIL);
127886629a8SRong Xu       NumNewD++;
128886629a8SRong Xu       LLVM_DEBUG(dbgs() << DIL->getFilename() << ":" << DIL->getLine() << ":"
129886629a8SRong Xu                         << DIL->getColumn() << ": add FS discriminator, from "
130886629a8SRong Xu                         << Discriminator << " -> " << NewD << "\n");
131886629a8SRong Xu       Changed = true;
132886629a8SRong Xu     }
133886629a8SRong Xu   }
134886629a8SRong Xu 
135886629a8SRong Xu   if (Changed) {
13682a0bb1aSRong Xu     createFSDiscriminatorVariable(MF.getFunction().getParent());
137886629a8SRong Xu     LLVM_DEBUG(dbgs() << "Num of FS Discriminators: " << NumNewD << "\n");
138*46776f75SMartin Storsjö     (void) NumNewD;
139886629a8SRong Xu   }
140886629a8SRong Xu 
141886629a8SRong Xu   return Changed;
142886629a8SRong Xu }
143