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