blob: f6bd5804261947f6f7c4e1cecb48872832677be2 [file] [log] [blame]
Mircea Trofinf1a49e82018-11-30 01:01:52 +00001//===- X86DiscriminateMemOps.cpp - Unique IDs for Mem Ops -----------------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Mircea Trofinf1a49e82018-11-30 01:01:52 +00006//
7//===----------------------------------------------------------------------===//
8///
9/// This pass aids profile-driven cache prefetch insertion by ensuring all
10/// instructions that have a memory operand are distinguishible from each other.
11///
12//===----------------------------------------------------------------------===//
13
14#include "X86.h"
15#include "X86InstrBuilder.h"
16#include "X86InstrInfo.h"
17#include "X86MachineFunctionInfo.h"
18#include "X86Subtarget.h"
19#include "llvm/CodeGen/MachineModuleInfo.h"
20#include "llvm/IR/DebugInfoMetadata.h"
21#include "llvm/ProfileData/SampleProf.h"
22#include "llvm/ProfileData/SampleProfReader.h"
Mircea Trofinb53eeb62018-12-21 22:48:50 +000023#include "llvm/Support/Debug.h"
Mircea Trofinf1a49e82018-11-30 01:01:52 +000024#include "llvm/Transforms/IPO/SampleProfile.h"
25using namespace llvm;
26
Mircea Trofin41c729e2018-12-13 19:40:59 +000027#define DEBUG_TYPE "x86-discriminate-memops"
28
Mircea Trofin519f42d2019-01-25 21:49:54 +000029static cl::opt<bool> EnableDiscriminateMemops(
30 DEBUG_TYPE, cl::init(false),
31 cl::desc("Generate unique debug info for each instruction with a memory "
32 "operand. Should be enabled for profile-drived cache prefetching, "
33 "both in the build of the binary being profiled, as well as in "
34 "the build of the binary consuming the profile."),
35 cl::Hidden);
36
Mircea Trofinf1a49e82018-11-30 01:01:52 +000037namespace {
38
39using Location = std::pair<StringRef, unsigned>;
40
41Location diToLocation(const DILocation *Loc) {
42 return std::make_pair(Loc->getFilename(), Loc->getLine());
43}
44
45/// Ensure each instruction having a memory operand has a distinct <LineNumber,
46/// Discriminator> pair.
47void updateDebugInfo(MachineInstr *MI, const DILocation *Loc) {
48 DebugLoc DL(Loc);
49 MI->setDebugLoc(DL);
50}
51
52class X86DiscriminateMemOps : public MachineFunctionPass {
53 bool runOnMachineFunction(MachineFunction &MF) override;
54 StringRef getPassName() const override {
55 return "X86 Discriminate Memory Operands";
56 }
57
58public:
59 static char ID;
60
61 /// Default construct and initialize the pass.
62 X86DiscriminateMemOps();
63};
64
65} // end anonymous namespace
66
67//===----------------------------------------------------------------------===//
68// Implementation
69//===----------------------------------------------------------------------===//
70
71char X86DiscriminateMemOps::ID = 0;
72
73/// Default construct and initialize the pass.
74X86DiscriminateMemOps::X86DiscriminateMemOps() : MachineFunctionPass(ID) {}
75
76bool X86DiscriminateMemOps::runOnMachineFunction(MachineFunction &MF) {
Mircea Trofin519f42d2019-01-25 21:49:54 +000077 if (!EnableDiscriminateMemops)
78 return false;
79
Mircea Trofinf1a49e82018-11-30 01:01:52 +000080 DISubprogram *FDI = MF.getFunction().getSubprogram();
81 if (!FDI || !FDI->getUnit()->getDebugInfoForProfiling())
82 return false;
83
84 // Have a default DILocation, if we find instructions with memops that don't
85 // have any debug info.
86 const DILocation *ReferenceDI =
87 DILocation::get(FDI->getContext(), FDI->getLine(), 0, FDI);
88
89 DenseMap<Location, unsigned> MemOpDiscriminators;
90 MemOpDiscriminators[diToLocation(ReferenceDI)] = 0;
91
92 // Figure out the largest discriminator issued for each Location. When we
93 // issue new discriminators, we can thus avoid issuing discriminators
94 // belonging to instructions that don't have memops. This isn't a requirement
95 // for the goals of this pass, however, it avoids unnecessary ambiguity.
96 for (auto &MBB : MF) {
97 for (auto &MI : MBB) {
98 const auto &DI = MI.getDebugLoc();
99 if (!DI)
100 continue;
101 Location Loc = diToLocation(DI);
102 MemOpDiscriminators[Loc] =
103 std::max(MemOpDiscriminators[Loc], DI->getBaseDiscriminator());
104 }
105 }
106
107 // Keep track of the discriminators seen at each Location. If an instruction's
108 // DebugInfo has a Location and discriminator we've already seen, replace its
109 // discriminator with a new one, to guarantee uniqueness.
110 DenseMap<Location, DenseSet<unsigned>> Seen;
111
112 bool Changed = false;
113 for (auto &MBB : MF) {
114 for (auto &MI : MBB) {
115 if (X86II::getMemoryOperandNo(MI.getDesc().TSFlags) < 0)
116 continue;
117 const DILocation *DI = MI.getDebugLoc();
118 if (!DI) {
119 DI = ReferenceDI;
120 }
Mircea Trofinb53eeb62018-12-21 22:48:50 +0000121 Location L = diToLocation(DI);
122 DenseSet<unsigned> &Set = Seen[L];
Mircea Trofinf1a49e82018-11-30 01:01:52 +0000123 const std::pair<DenseSet<unsigned>::iterator, bool> TryInsert =
124 Set.insert(DI->getBaseDiscriminator());
125 if (!TryInsert.second) {
Mircea Trofinb53eeb62018-12-21 22:48:50 +0000126 unsigned BF, DF, CI = 0;
127 DILocation::decodeDiscriminator(DI->getDiscriminator(), BF, DF, CI);
128 Optional<unsigned> EncodedDiscriminator = DILocation::encodeDiscriminator(
129 MemOpDiscriminators[L] + 1, DF, CI);
130
131 if (!EncodedDiscriminator) {
132 // FIXME(mtrofin): The assumption is that this scenario is infrequent/OK
133 // not to support. If evidence points otherwise, we can explore synthesizeing
134 // unique DIs by adding fake line numbers, or by constructing 64 bit
135 // discriminators.
136 LLVM_DEBUG(dbgs() << "Unable to create a unique discriminator "
137 "for instruction with memory operand in: "
Mircea Trofin41c729e2018-12-13 19:40:59 +0000138 << DI->getFilename() << " Line: " << DI->getLine()
139 << " Column: " << DI->getColumn()
Mircea Trofinb53eeb62018-12-21 22:48:50 +0000140 << ". This is likely due to a large macro expansion. \n");
141 continue;
Mircea Trofin41c729e2018-12-13 19:40:59 +0000142 }
Mircea Trofinb53eeb62018-12-21 22:48:50 +0000143 // Since we were able to encode, bump the MemOpDiscriminators.
144 ++MemOpDiscriminators[L];
145 DI = DI->cloneWithDiscriminator(EncodedDiscriminator.getValue());
146 updateDebugInfo(&MI, DI);
147 Changed = true;
148 std::pair<DenseSet<unsigned>::iterator, bool> MustInsert =
149 Set.insert(DI->getBaseDiscriminator());
Mircea Trofin499a66e2018-12-21 23:02:10 +0000150 (void)MustInsert; // Silence warning in release build.
Mircea Trofinb53eeb62018-12-21 22:48:50 +0000151 assert(MustInsert.second && "New discriminator shouldn't be present in set");
Mircea Trofinf1a49e82018-11-30 01:01:52 +0000152 }
153
154 // Bump the reference DI to avoid cramming discriminators on line 0.
155 // FIXME(mtrofin): pin ReferenceDI on blocks or first instruction with DI
156 // in a block. It's more consistent than just relying on the last memop
157 // instruction we happened to see.
158 ReferenceDI = DI;
159 }
160 }
161 return Changed;
162}
163
164FunctionPass *llvm::createX86DiscriminateMemOpsPass() {
165 return new X86DiscriminateMemOps();
166}