Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/Target/X86/X86DiscriminateMemOps.cpp
35266 views
1
//===- X86DiscriminateMemOps.cpp - Unique IDs for Mem Ops -----------------===//
2
//
3
// 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
6
//
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/MachineFunctionPass.h"
20
#include "llvm/CodeGen/MachineModuleInfo.h"
21
#include "llvm/IR/DebugInfoMetadata.h"
22
#include "llvm/ProfileData/SampleProf.h"
23
#include "llvm/ProfileData/SampleProfReader.h"
24
#include "llvm/Support/Debug.h"
25
#include "llvm/Transforms/IPO/SampleProfile.h"
26
#include <optional>
27
using namespace llvm;
28
29
#define DEBUG_TYPE "x86-discriminate-memops"
30
31
static cl::opt<bool> EnableDiscriminateMemops(
32
DEBUG_TYPE, cl::init(false),
33
cl::desc("Generate unique debug info for each instruction with a memory "
34
"operand. Should be enabled for profile-driven cache prefetching, "
35
"both in the build of the binary being profiled, as well as in "
36
"the build of the binary consuming the profile."),
37
cl::Hidden);
38
39
static cl::opt<bool> BypassPrefetchInstructions(
40
"x86-bypass-prefetch-instructions", cl::init(true),
41
cl::desc("When discriminating instructions with memory operands, ignore "
42
"prefetch instructions. This ensures the other memory operand "
43
"instructions have the same identifiers after inserting "
44
"prefetches, allowing for successive insertions."),
45
cl::Hidden);
46
47
namespace {
48
49
using Location = std::pair<StringRef, unsigned>;
50
51
Location diToLocation(const DILocation *Loc) {
52
return std::make_pair(Loc->getFilename(), Loc->getLine());
53
}
54
55
/// Ensure each instruction having a memory operand has a distinct <LineNumber,
56
/// Discriminator> pair.
57
void updateDebugInfo(MachineInstr *MI, const DILocation *Loc) {
58
DebugLoc DL(Loc);
59
MI->setDebugLoc(DL);
60
}
61
62
class X86DiscriminateMemOps : public MachineFunctionPass {
63
bool runOnMachineFunction(MachineFunction &MF) override;
64
StringRef getPassName() const override {
65
return "X86 Discriminate Memory Operands";
66
}
67
68
public:
69
static char ID;
70
71
/// Default construct and initialize the pass.
72
X86DiscriminateMemOps();
73
};
74
75
bool IsPrefetchOpcode(unsigned Opcode) {
76
return Opcode == X86::PREFETCHNTA || Opcode == X86::PREFETCHT0 ||
77
Opcode == X86::PREFETCHT1 || Opcode == X86::PREFETCHT2 ||
78
Opcode == X86::PREFETCHIT0 || Opcode == X86::PREFETCHIT1;
79
}
80
} // end anonymous namespace
81
82
//===----------------------------------------------------------------------===//
83
// Implementation
84
//===----------------------------------------------------------------------===//
85
86
char X86DiscriminateMemOps::ID = 0;
87
88
/// Default construct and initialize the pass.
89
X86DiscriminateMemOps::X86DiscriminateMemOps() : MachineFunctionPass(ID) {}
90
91
bool X86DiscriminateMemOps::runOnMachineFunction(MachineFunction &MF) {
92
if (!EnableDiscriminateMemops)
93
return false;
94
95
DISubprogram *FDI = MF.getFunction().getSubprogram();
96
if (!FDI || !FDI->getUnit()->getDebugInfoForProfiling())
97
return false;
98
99
// Have a default DILocation, if we find instructions with memops that don't
100
// have any debug info.
101
const DILocation *ReferenceDI =
102
DILocation::get(FDI->getContext(), FDI->getLine(), 0, FDI);
103
assert(ReferenceDI && "ReferenceDI should not be nullptr");
104
DenseMap<Location, unsigned> MemOpDiscriminators;
105
MemOpDiscriminators[diToLocation(ReferenceDI)] = 0;
106
107
// Figure out the largest discriminator issued for each Location. When we
108
// issue new discriminators, we can thus avoid issuing discriminators
109
// belonging to instructions that don't have memops. This isn't a requirement
110
// for the goals of this pass, however, it avoids unnecessary ambiguity.
111
for (auto &MBB : MF) {
112
for (auto &MI : MBB) {
113
const auto &DI = MI.getDebugLoc();
114
if (!DI)
115
continue;
116
if (BypassPrefetchInstructions && IsPrefetchOpcode(MI.getDesc().Opcode))
117
continue;
118
Location Loc = diToLocation(DI);
119
MemOpDiscriminators[Loc] =
120
std::max(MemOpDiscriminators[Loc], DI->getBaseDiscriminator());
121
}
122
}
123
124
// Keep track of the discriminators seen at each Location. If an instruction's
125
// DebugInfo has a Location and discriminator we've already seen, replace its
126
// discriminator with a new one, to guarantee uniqueness.
127
DenseMap<Location, DenseSet<unsigned>> Seen;
128
129
bool Changed = false;
130
for (auto &MBB : MF) {
131
for (auto &MI : MBB) {
132
if (X86II::getMemoryOperandNo(MI.getDesc().TSFlags) < 0)
133
continue;
134
if (BypassPrefetchInstructions && IsPrefetchOpcode(MI.getDesc().Opcode))
135
continue;
136
const DILocation *DI = MI.getDebugLoc();
137
bool HasDebug = DI;
138
if (!HasDebug) {
139
DI = ReferenceDI;
140
}
141
Location L = diToLocation(DI);
142
DenseSet<unsigned> &Set = Seen[L];
143
const std::pair<DenseSet<unsigned>::iterator, bool> TryInsert =
144
Set.insert(DI->getBaseDiscriminator());
145
if (!TryInsert.second || !HasDebug) {
146
unsigned BF, DF, CI = 0;
147
DILocation::decodeDiscriminator(DI->getDiscriminator(), BF, DF, CI);
148
std::optional<unsigned> EncodedDiscriminator =
149
DILocation::encodeDiscriminator(MemOpDiscriminators[L] + 1, DF, CI);
150
151
if (!EncodedDiscriminator) {
152
// FIXME(mtrofin): The assumption is that this scenario is infrequent/OK
153
// not to support. If evidence points otherwise, we can explore synthesizeing
154
// unique DIs by adding fake line numbers, or by constructing 64 bit
155
// discriminators.
156
LLVM_DEBUG(dbgs() << "Unable to create a unique discriminator "
157
"for instruction with memory operand in: "
158
<< DI->getFilename() << " Line: " << DI->getLine()
159
<< " Column: " << DI->getColumn()
160
<< ". This is likely due to a large macro expansion. \n");
161
continue;
162
}
163
// Since we were able to encode, bump the MemOpDiscriminators.
164
++MemOpDiscriminators[L];
165
DI = DI->cloneWithDiscriminator(*EncodedDiscriminator);
166
assert(DI && "DI should not be nullptr");
167
updateDebugInfo(&MI, DI);
168
Changed = true;
169
std::pair<DenseSet<unsigned>::iterator, bool> MustInsert =
170
Set.insert(DI->getBaseDiscriminator());
171
(void)MustInsert; // Silence warning in release build.
172
assert(MustInsert.second && "New discriminator shouldn't be present in set");
173
}
174
175
// Bump the reference DI to avoid cramming discriminators on line 0.
176
// FIXME(mtrofin): pin ReferenceDI on blocks or first instruction with DI
177
// in a block. It's more consistent than just relying on the last memop
178
// instruction we happened to see.
179
ReferenceDI = DI;
180
}
181
}
182
return Changed;
183
}
184
185
FunctionPass *llvm::createX86DiscriminateMemOpsPass() {
186
return new X86DiscriminateMemOps();
187
}
188
189