LLVM 19.0.0git
X86DiscriminateMemOps.cpp
Go to the documentation of this file.
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"
18#include "X86Subtarget.h"
24#include "llvm/Support/Debug.h"
26#include <optional>
27using namespace llvm;
28
29#define DEBUG_TYPE "x86-discriminate-memops"
30
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."),
38
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."),
46
47namespace {
48
49using Location = std::pair<StringRef, unsigned>;
50
51Location 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.
57void updateDebugInfo(MachineInstr *MI, const DILocation *Loc) {
58 DebugLoc DL(Loc);
59 MI->setDebugLoc(DL);
60}
61
62class X86DiscriminateMemOps : public MachineFunctionPass {
63 bool runOnMachineFunction(MachineFunction &MF) override;
64 StringRef getPassName() const override {
65 return "X86 Discriminate Memory Operands";
66 }
67
68public:
69 static char ID;
70
71 /// Default construct and initialize the pass.
72 X86DiscriminateMemOps();
73};
74
75bool 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
86char X86DiscriminateMemOps::ID = 0;
87
88/// Default construct and initialize the pass.
89X86DiscriminateMemOps::X86DiscriminateMemOps() : MachineFunctionPass(ID) {}
90
91bool X86DiscriminateMemOps::runOnMachineFunction(MachineFunction &MF) {
93 return false;
94
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.
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
186 return new X86DiscriminateMemOps();
187}
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
#define LLVM_DEBUG(X)
Definition: Debug.h:101
static RegisterPass< DebugifyFunctionPass > DF("debugify-function", "Attach debug info to a function")
IRTranslator LLVM IR MI
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file provides the interface for the sampled PGO loader pass.
static cl::opt< bool > EnableDiscriminateMemops(DEBUG_TYPE, cl::init(false), cl::desc("Generate unique debug info for each instruction with a memory " "operand. Should be enabled for profile-driven cache prefetching, " "both in the build of the binary being profiled, as well as in " "the build of the binary consuming the profile."), cl::Hidden)
static cl::opt< bool > BypassPrefetchInstructions("x86-bypass-prefetch-instructions", cl::init(true), cl::desc("When discriminating instructions with memory operands, ignore " "prefetch instructions. This ensures the other memory operand " "instructions have the same identifiers after inserting " "prefetches, allowing for successive insertions."), cl::Hidden)
#define DEBUG_TYPE
Debug location.
static std::optional< unsigned > encodeDiscriminator(unsigned BD, unsigned DF, unsigned CI)
Raw encoding of the discriminator.
static void decodeDiscriminator(unsigned D, unsigned &BD, unsigned &DF, unsigned &CI)
Raw decoder for values in an encoded discriminator D.
unsigned getBaseDiscriminator() const
Returns the base discriminator stored in the discriminator.
const DILocation * cloneWithDiscriminator(unsigned Discriminator) const
Returns a new DILocation with updated Discriminator.
Subprogram description.
A debug info location.
Definition: DebugLoc.h:33
Implements a dense probed hash-table based set.
Definition: DenseSet.h:271
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:311
DISubprogram * getSubprogram() const
Get the attached subprogram.
Definition: Metadata.cpp:1831
LLVMContext & getContext() const
Definition: Metadata.h:1231
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
virtual bool runOnMachineFunction(MachineFunction &MF)=0
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
Function & getFunction()
Return the LLVM function that this machine code represents.
Representation of each machine instruction.
Definition: MachineInstr.h:69
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
Definition: Pass.cpp:81
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
std::pair< iterator, bool > insert(const ValueT &V)
Definition: DenseSet.h:206
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
int getMemoryOperandNo(uint64_t TSFlags)
Definition: X86BaseInfo.h:1022
initializer< Ty > init(const Ty &Val)
Definition: CommandLine.h:450
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
FunctionPass * createX86DiscriminateMemOpsPass()
This pass ensures instructions featuring a memory operand have distinctive <LineNumber,...