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